LCOV - code coverage report
Current view: top level - security/manager/ssl - nsSecureBrowserUIImpl.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 344 463 74.3 %
Date: 2017-07-14 16:53:18 Functions: 24 26 92.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsSecureBrowserUIImpl.h"
       7             : 
       8             : #include "imgIRequest.h"
       9             : #include "mozilla/Assertions.h"
      10             : #include "mozilla/IntegerPrintfMacros.h"
      11             : #include "mozilla/Logging.h"
      12             : #include "nsCURILoader.h"
      13             : #include "nsIAssociatedContentSecurity.h"
      14             : #include "nsIChannel.h"
      15             : #include "nsIDOMWindow.h"
      16             : #include "nsIDocShell.h"
      17             : #include "nsIDocShellTreeItem.h"
      18             : #include "nsIDocument.h"
      19             : #include "nsIFTPChannel.h"
      20             : #include "nsIFileChannel.h"
      21             : #include "nsIHttpChannel.h"
      22             : #include "nsIInterfaceRequestorUtils.h"
      23             : #include "nsIProtocolHandler.h"
      24             : #include "nsISSLStatus.h"
      25             : #include "nsISecurityInfoProvider.h"
      26             : #include "nsIServiceManager.h"
      27             : #include "nsITransportSecurityInfo.h"
      28             : #include "nsIWebProgress.h"
      29             : #include "nsIWyciwygChannel.h"
      30             : #include "nsNetCID.h"
      31             : #include "nsNetUtil.h"
      32             : #include "nsPIDOMWindow.h"
      33             : #include "nsThreadUtils.h"
      34             : #include "nspr.h"
      35             : #include "nsString.h"
      36             : 
      37             : using namespace mozilla;
      38             : 
      39             : LazyLogModule gSecureDocLog("nsSecureBrowserUI");
      40             : 
      41             : struct RequestHashEntry : PLDHashEntryHdr {
      42             :     void *r;
      43             : };
      44             : 
      45             : static bool
      46           5 : RequestMapMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
      47             : {
      48           5 :   const RequestHashEntry *entry = static_cast<const RequestHashEntry*>(hdr);
      49           5 :   return entry->r == key;
      50             : }
      51             : 
      52             : static void
      53           5 : RequestMapInitEntry(PLDHashEntryHdr *hdr, const void *key)
      54             : {
      55           5 :   RequestHashEntry *entry = static_cast<RequestHashEntry*>(hdr);
      56           5 :   entry->r = (void*)key;
      57           5 : }
      58             : 
      59             : static const PLDHashTableOps gMapOps = {
      60             :   PLDHashTable::HashVoidPtrKeyStub,
      61             :   RequestMapMatchEntry,
      62             :   PLDHashTable::MoveEntryStub,
      63             :   PLDHashTable::ClearEntryStub,
      64             :   RequestMapInitEntry
      65             : };
      66             : 
      67           2 : nsSecureBrowserUIImpl::nsSecureBrowserUIImpl()
      68             :   : mNotifiedSecurityState(lis_no_security)
      69             :   , mNotifiedToplevelIsEV(false)
      70             :   , mNewToplevelSecurityState(STATE_IS_INSECURE)
      71             :   , mNewToplevelIsEV(false)
      72             :   , mNewToplevelSecurityStateKnown(true)
      73             :   , mIsViewSource(false)
      74             :   , mSubRequestsBrokenSecurity(0)
      75             :   , mSubRequestsNoSecurity(0)
      76             :   , mCertUserOverridden(false)
      77             :   , mRestoreSubrequests(false)
      78             :   , mOnLocationChangeSeen(false)
      79             : #ifdef DEBUG
      80             :   , mEntered(false)
      81             : #endif
      82           2 :   , mTransferringRequests(&gMapOps, sizeof(RequestHashEntry))
      83             : {
      84           2 :   MOZ_ASSERT(NS_IsMainThread());
      85             : 
      86           2 :   ResetStateTracking();
      87           2 : }
      88             : 
      89         301 : NS_IMPL_ISUPPORTS(nsSecureBrowserUIImpl,
      90             :                   nsISecureBrowserUI,
      91             :                   nsIWebProgressListener,
      92             :                   nsISupportsWeakReference,
      93             :                   nsISSLStatusProvider)
      94             : 
      95             : NS_IMETHODIMP
      96           2 : nsSecureBrowserUIImpl::Init(mozIDOMWindowProxy* aWindow)
      97             : {
      98           2 :   MOZ_ASSERT(NS_IsMainThread());
      99             : 
     100           2 :   if (MOZ_LOG_TEST(gSecureDocLog, LogLevel::Debug)) {
     101           0 :     nsCOMPtr<nsIDOMWindow> window(do_QueryReferent(mWindow));
     102             : 
     103           0 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     104             :            ("SecureUI:%p: Init: mWindow: %p, aWindow: %p\n", this,
     105             :             window.get(), aWindow));
     106             :   }
     107             : 
     108           2 :   if (!aWindow) {
     109           0 :     NS_WARNING("Null window passed to nsSecureBrowserUIImpl::Init()");
     110           0 :     return NS_ERROR_INVALID_ARG;
     111             :   }
     112             : 
     113           2 :   if (mWindow) {
     114           0 :     NS_WARNING("Trying to init an nsSecureBrowserUIImpl twice");
     115           0 :     return NS_ERROR_ALREADY_INITIALIZED;
     116             :   }
     117             : 
     118             :   nsresult rv;
     119           2 :   mWindow = do_GetWeakReference(aWindow, &rv);
     120           2 :   NS_ENSURE_SUCCESS(rv, rv);
     121             : 
     122           2 :   auto* piwindow = nsPIDOMWindowOuter::From(aWindow);
     123           2 :   nsIDocShell *docShell = piwindow->GetDocShell();
     124             : 
     125             :   // The Docshell will own the SecureBrowserUI object
     126           2 :   if (!docShell)
     127           0 :     return NS_ERROR_FAILURE;
     128             : 
     129           2 :   docShell->SetSecurityUI(this);
     130             : 
     131             :   /* GetWebProgress(mWindow) */
     132             :   // hook up to the webprogress notifications.
     133           4 :   nsCOMPtr<nsIWebProgress> wp(do_GetInterface(docShell));
     134           2 :   if (!wp) return NS_ERROR_FAILURE;
     135             :   /* end GetWebProgress */
     136             : 
     137           4 :   wp->AddProgressListener(static_cast<nsIWebProgressListener*>(this),
     138             :                           nsIWebProgress::NOTIFY_STATE_ALL |
     139             :                           nsIWebProgress::NOTIFY_LOCATION  |
     140           4 :                           nsIWebProgress::NOTIFY_SECURITY);
     141             : 
     142             : 
     143           2 :   return NS_OK;
     144             : }
     145             : 
     146             : NS_IMETHODIMP
     147           2 : nsSecureBrowserUIImpl::GetState(uint32_t* aState)
     148             : {
     149           2 :   MOZ_ASSERT(NS_IsMainThread());
     150           2 :   return MapInternalToExternalState(aState, mNotifiedSecurityState,
     151           4 :                                     mNotifiedToplevelIsEV);
     152             : }
     153             : 
     154             : // static
     155             : already_AddRefed<nsISupports>
     156          33 : nsSecureBrowserUIImpl::ExtractSecurityInfo(nsIRequest* aRequest)
     157             : {
     158          66 :   nsCOMPtr<nsISupports> retval;
     159          66 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
     160          33 :   if (channel)
     161          26 :     channel->GetSecurityInfo(getter_AddRefs(retval));
     162             : 
     163          33 :   if (!retval) {
     164          66 :     nsCOMPtr<nsISecurityInfoProvider> provider(do_QueryInterface(aRequest));
     165          33 :     if (provider)
     166           0 :       provider->GetSecurityInfo(getter_AddRefs(retval));
     167             :   }
     168             : 
     169          66 :   return retval.forget();
     170             : }
     171             : 
     172             : nsresult
     173           2 : nsSecureBrowserUIImpl::MapInternalToExternalState(uint32_t* aState, lockIconState lock, bool ev)
     174             : {
     175           2 :   NS_ENSURE_ARG(aState);
     176             : 
     177           2 :   switch (lock)
     178             :   {
     179             :     case lis_broken_security:
     180           0 :       *aState = STATE_IS_BROKEN;
     181           0 :       break;
     182             : 
     183             :     case lis_mixed_security:
     184           0 :       *aState = STATE_IS_BROKEN;
     185           0 :       break;
     186             : 
     187             :     case lis_high_security:
     188           0 :       *aState = STATE_IS_SECURE | STATE_SECURE_HIGH;
     189           0 :       break;
     190             : 
     191             :     default:
     192             :     case lis_no_security:
     193           2 :       *aState = STATE_IS_INSECURE;
     194           2 :       break;
     195             :   }
     196             : 
     197           2 :   if (ev && (*aState & STATE_IS_SECURE))
     198           0 :     *aState |= nsIWebProgressListener::STATE_IDENTITY_EV_TOPLEVEL;
     199             : 
     200           2 :   if (mCertUserOverridden && (*aState & STATE_IS_SECURE)) {
     201           0 :     *aState |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
     202             :   }
     203             : 
     204           4 :   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
     205           2 :   if (!docShell)
     206           0 :     return NS_OK;
     207             : 
     208             :   // For content docShell's, the mixed content security state is set on the root docShell.
     209           2 :   if (docShell->ItemType() == nsIDocShellTreeItem::typeContent) {
     210           4 :     nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(docShell));
     211           4 :     nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
     212           2 :     docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
     213           2 :     MOZ_ASSERT(sameTypeRoot,
     214             :                "No document shell root tree item from document shell tree item!");
     215           2 :     docShell = do_QueryInterface(sameTypeRoot);
     216           2 :     if (!docShell)
     217           0 :       return NS_OK;
     218             :   }
     219             : 
     220             :   // Has a Mixed Content Load initiated in nsMixedContentBlocker?
     221             :   // * If not, the state should not be broken because of mixed content;
     222             :   // overriding the previous state if it is inaccurately flagged as mixed.
     223           2 :   if (lock == lis_mixed_security &&
     224           0 :       !docShell->GetHasMixedActiveContentLoaded() &&
     225           0 :       !docShell->GetHasMixedDisplayContentLoaded() &&
     226           2 :       !docShell->GetHasMixedActiveContentBlocked() &&
     227           0 :       !docShell->GetHasMixedDisplayContentBlocked()) {
     228           0 :     *aState = STATE_IS_SECURE;
     229           0 :     if (ev) {
     230           0 :       *aState |= nsIWebProgressListener::STATE_IDENTITY_EV_TOPLEVEL;
     231             :     }
     232             :   }
     233             :   // * If so, the state should be broken or insecure; overriding the previous
     234             :   // state set by the lock parameter.
     235           2 :   uint32_t tempState = STATE_IS_BROKEN;
     236           2 :   if (lock == lis_no_security) {
     237             :       // this is to ensure that http: pages with mixed content in nested
     238             :       // iframes don't get marked as broken instead of insecure
     239           2 :       tempState = STATE_IS_INSECURE;
     240             :   }
     241           2 :   if (docShell->GetHasMixedActiveContentLoaded() &&
     242           0 :       docShell->GetHasMixedDisplayContentLoaded()) {
     243           0 :       *aState = tempState |
     244           0 :                 nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
     245             :                 nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT;
     246           2 :   } else if (docShell->GetHasMixedActiveContentLoaded()) {
     247           0 :       *aState = tempState |
     248             :                 nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT;
     249           2 :   } else if (docShell->GetHasMixedDisplayContentLoaded()) {
     250           0 :       *aState = tempState |
     251             :                 nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT;
     252             :   }
     253             : 
     254           2 :   if (mCertUserOverridden) {
     255           0 :     *aState |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
     256             :   }
     257             : 
     258             :   // Has Mixed Content Been Blocked in nsMixedContentBlocker?
     259           2 :   if (docShell->GetHasMixedActiveContentBlocked())
     260           0 :     *aState |= nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT;
     261             : 
     262           2 :   if (docShell->GetHasMixedDisplayContentBlocked())
     263           0 :     *aState |= nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT;
     264             : 
     265             :   // Has Tracking Content been Blocked?
     266           2 :   if (docShell->GetHasTrackingContentBlocked())
     267           0 :     *aState |= nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT;
     268             : 
     269           2 :   if (docShell->GetHasTrackingContentLoaded())
     270           0 :     *aState |= nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT;
     271             : 
     272           2 :   return NS_OK;
     273             : }
     274             : 
     275             : NS_IMETHODIMP
     276           2 : nsSecureBrowserUIImpl::SetDocShell(nsIDocShell* aDocShell)
     277             : {
     278           2 :   MOZ_ASSERT(NS_IsMainThread());
     279             :   nsresult rv;
     280           2 :   mDocShell = do_GetWeakReference(aDocShell, &rv);
     281           2 :   return rv;
     282             : }
     283             : 
     284           5 : static uint32_t GetSecurityStateFromSecurityInfoAndRequest(nsISupports* info,
     285             :                                                            nsIRequest* request)
     286             : {
     287             :   nsresult res;
     288             :   uint32_t securityState;
     289             : 
     290          10 :   nsCOMPtr<nsITransportSecurityInfo> psmInfo(do_QueryInterface(info));
     291           5 :   if (!psmInfo) {
     292           5 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - no nsITransportSecurityInfo for %p\n",
     293             :                                          (nsISupports *)info));
     294           5 :     return nsIWebProgressListener::STATE_IS_INSECURE;
     295             :   }
     296           0 :   MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - info is %p\n",
     297             :                                        (nsISupports *)info));
     298             : 
     299           0 :   res = psmInfo->GetSecurityState(&securityState);
     300           0 :   if (NS_FAILED(res)) {
     301           0 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - GetSecurityState failed: %" PRIu32 "\n",
     302             :                                              static_cast<uint32_t>(res)));
     303           0 :     securityState = nsIWebProgressListener::STATE_IS_BROKEN;
     304             :   }
     305             : 
     306           0 :   if (securityState != nsIWebProgressListener::STATE_IS_INSECURE) {
     307             :     // A secure connection does not yield a secure per-uri channel if the
     308             :     // scheme is plain http.
     309             : 
     310           0 :     nsCOMPtr<nsIURI> uri;
     311           0 :     nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
     312           0 :     if (channel) {
     313           0 :       channel->GetURI(getter_AddRefs(uri));
     314             :     } else {
     315           0 :       nsCOMPtr<imgIRequest> imgRequest(do_QueryInterface(request));
     316           0 :       if (imgRequest) {
     317           0 :         imgRequest->GetURI(getter_AddRefs(uri));
     318             :       }
     319             :     }
     320           0 :     if (uri) {
     321             :       bool isHttp, isFtp;
     322           0 :       if ((NS_SUCCEEDED(uri->SchemeIs("http", &isHttp)) && isHttp) ||
     323           0 :           (NS_SUCCEEDED(uri->SchemeIs("ftp", &isFtp)) && isFtp)) {
     324           0 :         MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - "
     325             :                                              "channel scheme is insecure.\n"));
     326           0 :         securityState = nsIWebProgressListener::STATE_IS_INSECURE;
     327             :       }
     328             :     }
     329             :   }
     330             : 
     331           0 :   MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - Returning %d\n",
     332             :                                        securityState));
     333           0 :   return securityState;
     334             : }
     335             : 
     336             : 
     337             : //  nsIWebProgressListener
     338             : NS_IMETHODIMP
     339           0 : nsSecureBrowserUIImpl::OnProgressChange(nsIWebProgress*, nsIRequest*, int32_t,
     340             :                                         int32_t, int32_t, int32_t)
     341             : {
     342           0 :   MOZ_ASSERT_UNREACHABLE("Should have been excluded in AddProgressListener()");
     343             :   return NS_OK;
     344             : }
     345             : 
     346             : void
     347           5 : nsSecureBrowserUIImpl::ResetStateTracking()
     348             : {
     349           5 :   mDocumentRequestsInProgress = 0;
     350           5 :   mTransferringRequests.Clear();
     351           5 : }
     352             : 
     353             : void
     354           3 : nsSecureBrowserUIImpl::EvaluateAndUpdateSecurityState(nsIRequest* aRequest,
     355             :                                                       nsISupports* info,
     356             :                                                       bool withNewLocation,
     357             :                                                       bool withNewSink)
     358             : {
     359           3 :   mNewToplevelIsEV = false;
     360             : 
     361           3 :   bool updateStatus = false;
     362           6 :   nsCOMPtr<nsISSLStatus> temp_SSLStatus;
     363             : 
     364           3 :   mNewToplevelSecurityState =
     365           3 :     GetSecurityStateFromSecurityInfoAndRequest(info, aRequest);
     366             : 
     367           3 :   MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     368             :           ("SecureUI:%p: OnStateChange: remember mNewToplevelSecurityState => %x\n",
     369             :            this, mNewToplevelSecurityState));
     370             : 
     371           6 :   nsCOMPtr<nsISSLStatusProvider> sp(do_QueryInterface(info));
     372           3 :   if (sp) {
     373             :     // Ignore result
     374           0 :     updateStatus = true;
     375           0 :     (void) sp->GetSSLStatus(getter_AddRefs(temp_SSLStatus));
     376           0 :     if (temp_SSLStatus) {
     377             :       bool aTemp;
     378           0 :       if (NS_SUCCEEDED(temp_SSLStatus->GetIsExtendedValidation(&aTemp))) {
     379           0 :         mNewToplevelIsEV = aTemp;
     380             :       }
     381             :     }
     382             :   }
     383             : 
     384           3 :   mNewToplevelSecurityStateKnown = true;
     385           3 :   if (updateStatus) {
     386           0 :     mSSLStatus = temp_SSLStatus;
     387             :   }
     388           3 :   MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     389             :          ("SecureUI:%p: remember securityInfo %p\n", this,
     390             :           info));
     391             :   nsCOMPtr<nsIAssociatedContentSecurity> associatedContentSecurityFromRequest(
     392           6 :     do_QueryInterface(aRequest));
     393           3 :   if (associatedContentSecurityFromRequest) {
     394           0 :     mCurrentToplevelSecurityInfo = aRequest;
     395             :   } else {
     396           3 :     mCurrentToplevelSecurityInfo = info;
     397             :   }
     398             : 
     399             :   // The subrequest counters are now in sync with mCurrentToplevelSecurityInfo,
     400             :   // don't restore after top level document load finishes.
     401           3 :   mRestoreSubrequests = false;
     402             : 
     403           3 :   UpdateSecurityState(aRequest, withNewLocation, withNewSink || updateStatus);
     404           3 : }
     405             : 
     406             : void
     407           2 : nsSecureBrowserUIImpl::UpdateSubrequestMembers(nsISupports* securityInfo,
     408             :                                                nsIRequest* request)
     409             : {
     410             :   // For wyciwyg channels in subdocuments we only update our
     411             :   // subrequest state members.
     412             :   uint32_t reqState = GetSecurityStateFromSecurityInfoAndRequest(securityInfo,
     413           2 :                                                                  request);
     414             : 
     415           2 :   if (reqState & STATE_IS_SECURE) {
     416             :     // do nothing
     417           2 :   } else if (reqState & STATE_IS_BROKEN) {
     418           0 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     419             :            ("SecureUI:%p: OnStateChange: subreq BROKEN\n", this));
     420           0 :     ++mSubRequestsBrokenSecurity;
     421             :   } else {
     422           2 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     423             :            ("SecureUI:%p: OnStateChange: subreq INSECURE\n", this));
     424           2 :     ++mSubRequestsNoSecurity;
     425             :   }
     426           2 : }
     427             : 
     428             : NS_IMETHODIMP
     429          31 : nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
     430             :                                      nsIRequest* aRequest,
     431             :                                      uint32_t aProgressStateFlags,
     432             :                                      nsresult aStatus)
     433             : {
     434          31 :   MOZ_ASSERT(NS_IsMainThread());
     435          62 :   ReentrancyGuard guard(*this);
     436             :   /*
     437             :     All discussion, unless otherwise mentioned, only refers to
     438             :     http, https, file or wyciwig requests.
     439             : 
     440             : 
     441             :     Redirects are evil, well, some of them.
     442             :     There are multiple forms of redirects.
     443             : 
     444             :     Redirects caused by http refresh content are ok, because experiments show,
     445             :     with those redirects, the old page contents and their requests will come to STOP
     446             :     completely, before any progress from new refreshed page content is reported.
     447             :     So we can safely treat them as separate page loading transactions.
     448             : 
     449             :     Evil are redirects at the http protocol level, like code 302.
     450             : 
     451             :     If the toplevel documents gets replaced, i.e. redirected with 302, we do not care for the
     452             :     security state of the initial transaction, which has now been redirected,
     453             :     we only care for the new page load.
     454             : 
     455             :     For the implementation of the security UI, we make an assumption, that is hopefully true.
     456             : 
     457             :     Imagine, the received page that was delivered with the 302 redirection answer,
     458             :     also delivered html content.
     459             : 
     460             :     What happens if the parser starts to analyze the content and tries to load contained sub objects?
     461             : 
     462             :     In that case we would see start and stop requests for subdocuments, some for the previous document,
     463             :     some for the new target document. And only those for the new toplevel document may be
     464             :     taken into consideration, when deciding about the security state of the next toplevel document.
     465             : 
     466             :     Because security state is being looked at, when loading stops for (sub)documents, this
     467             :     could cause real confusion, because we have to decide, whether an incoming progress
     468             :     belongs to the new toplevel page, or the previous, already redirected page.
     469             : 
     470             :     Can we simplify here?
     471             : 
     472             :     If a redirect at the http protocol level is seen, can we safely assume, its html content
     473             :     will not be parsed, anylzed, and no embedded objects will get loaded (css, js, images),
     474             :     because the redirect is already happening?
     475             : 
     476             :     If we can assume that, this really simplify things. Because we will never see notification
     477             :     for sub requests that need to get ignored.
     478             : 
     479             :     I would like to make this assumption for now, but please let me (kaie) know if I'm wrong.
     480             : 
     481             :     Excurse:
     482             :       If my assumption is wrong, then we would require more tracking information.
     483             :       We need to keep lists of all pointers to request object that had been seen since the
     484             :       last toplevel start event.
     485             :       If the start for a redirected page is seen, the list of releveant object must be cleared,
     486             :       and only progress for requests which start after it must be analyzed.
     487             :       All other events must be ignored, as they belong to now irrelevant previous top level documents.
     488             : 
     489             : 
     490             :     Frames are also evil.
     491             : 
     492             :     First we need a decision.
     493             :     kaie thinks:
     494             :       Only if the toplevel frame is secure, we should try to display secure lock icons.
     495             :       If some of the inner contents are insecure, we display mixed mode.
     496             : 
     497             :       But if the top level frame is not secure, why indicate a mixed lock icon at all?
     498             :       I think we should always display an open lock icon, if the top level frameset is insecure.
     499             : 
     500             :       That's the way Netscape Communicator behaves, and I think we should do the same.
     501             : 
     502             :       The user will not know which parts are secure and which are not,
     503             :       and any certificate information, displayed in the tooltip or in the "page info"
     504             :       will only be relevant for some subframe(s), and the user will not know which ones,
     505             :       so we shouldn't display it as a general attribute of the displayed page.
     506             : 
     507             :     Why are frames evil?
     508             : 
     509             :     Because the progress for the toplevel frame document is not easily distinguishable
     510             :     from subframes. The same STATE bits are reported.
     511             : 
     512             :     While at first sight, when a new page load happens,
     513             :     the toplevel frameset document has also the STATE_IS_NETWORK bit in it.
     514             :     But this can't really be used. Because in case that document causes a http 302 redirect,
     515             :     the real top level frameset will no longer have that bit.
     516             : 
     517             :     But we need some way to distinguish top level frames from inner frames.
     518             : 
     519             :     I saw that the web progress we get delivered has a reference to the toplevel DOM window.
     520             : 
     521             :     I suggest, we look at all incoming requests.
     522             :     If a request is NOT for the toplevel DOM window, we will always treat it as a subdocument request,
     523             :     regardless of whether the load flags indicate a top level document.
     524             :   */
     525             : 
     526          62 :   nsCOMPtr<mozIDOMWindowProxy> windowForProgress;
     527          31 :   aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress));
     528             : 
     529          62 :   nsCOMPtr<mozIDOMWindowProxy> window(do_QueryReferent(mWindow));
     530          31 :   MOZ_ASSERT(window, "Window has gone away?!");
     531             : 
     532          31 :   if (!mIOService) {
     533           2 :     mIOService = do_GetService(NS_IOSERVICE_CONTRACTID);
     534             :   }
     535             : 
     536          31 :   bool isNoContentResponse = false;
     537          62 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
     538          31 :   if (httpChannel)
     539             :   {
     540             :     uint32_t response;
     541          19 :     isNoContentResponse = NS_SUCCEEDED(httpChannel->GetResponseStatus(&response)) &&
     542          16 :         (response == 204 || response == 205);
     543             :   }
     544          31 :   const bool isToplevelProgress = (windowForProgress.get() == window.get()) && !isNoContentResponse;
     545             : 
     546          31 :   if (windowForProgress)
     547             :   {
     548          31 :     if (isToplevelProgress)
     549             :     {
     550          31 :       MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     551             :              ("SecureUI:%p: OnStateChange: progress: for toplevel\n", this));
     552             :     }
     553             :     else
     554             :     {
     555           0 :       MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     556             :              ("SecureUI:%p: OnStateChange: progress: for something else\n", this));
     557             :     }
     558             :   }
     559             :   else
     560             :   {
     561           0 :       MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     562             :              ("SecureUI:%p: OnStateChange: progress: no window known\n", this));
     563             :   }
     564             : 
     565          31 :   MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     566             :          ("SecureUI:%p: OnStateChange\n", this));
     567             : 
     568          31 :   if (mIsViewSource) {
     569           0 :     return NS_OK;
     570             :   }
     571             : 
     572          31 :   if (!aRequest)
     573             :   {
     574           0 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     575             :            ("SecureUI:%p: OnStateChange with null request\n", this));
     576           0 :     return NS_ERROR_NULL_POINTER;
     577             :   }
     578             : 
     579          31 :   if (MOZ_LOG_TEST(gSecureDocLog, LogLevel::Debug)) {
     580           0 :     nsXPIDLCString reqname;
     581           0 :     aRequest->GetName(reqname);
     582           0 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     583             :            ("SecureUI:%p: %p %p OnStateChange %x %s\n", this, aWebProgress,
     584             :             aRequest, aProgressStateFlags, reqname.get()));
     585             :   }
     586             : 
     587          62 :   nsCOMPtr<nsISupports> securityInfo(ExtractSecurityInfo(aRequest));
     588             : 
     589          62 :   nsCOMPtr<nsIURI> uri;
     590          62 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
     591          31 :   if (channel) {
     592          25 :     channel->GetURI(getter_AddRefs(uri));
     593             :   }
     594             : 
     595          62 :   nsCOMPtr<imgIRequest> imgRequest(do_QueryInterface(aRequest));
     596          31 :   if (imgRequest) {
     597           0 :     MOZ_ASSERT(!channel, "Request channel somehow not available");
     598             :     // for image requests, we get the URI from here
     599           0 :     imgRequest->GetURI(getter_AddRefs(uri));
     600             :   }
     601             : 
     602          31 :   if (uri) {
     603             :     bool vs;
     604          25 :     if (NS_SUCCEEDED(uri->SchemeIs("javascript", &vs)) && vs) {
     605             :       // We ignore the progress events for javascript URLs.
     606             :       // If a document loading gets triggered, we will see more events.
     607           0 :       return NS_OK;
     608             :     }
     609             :   }
     610             : 
     611          31 :   uint32_t loadFlags = 0;
     612          31 :   aRequest->GetLoadFlags(&loadFlags);
     613             : 
     614          31 :   if (aProgressStateFlags & STATE_START
     615          10 :       &&
     616          10 :       aProgressStateFlags & STATE_IS_REQUEST
     617          10 :       &&
     618             :       isToplevelProgress
     619          10 :       &&
     620          10 :       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
     621             :   {
     622           3 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     623             :            ("SecureUI:%p: OnStateChange: SOMETHING STARTS FOR TOPMOST DOCUMENT\n", this));
     624             :   }
     625             : 
     626          31 :   if (aProgressStateFlags & STATE_STOP
     627          16 :       &&
     628          16 :       aProgressStateFlags & STATE_IS_REQUEST
     629          10 :       &&
     630             :       isToplevelProgress
     631          10 :       &&
     632          10 :       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
     633             :   {
     634           3 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     635             :            ("SecureUI:%p: OnStateChange: SOMETHING STOPS FOR TOPMOST DOCUMENT\n", this));
     636             :   }
     637             : 
     638          31 :   bool isSubDocumentRelevant = true;
     639             : 
     640             :   // We are only interested in requests that load in the browser window...
     641          31 :   if (!imgRequest) { // is not imgRequest
     642          62 :     nsCOMPtr<nsIHttpChannel> httpRequest(do_QueryInterface(aRequest));
     643          31 :     if (!httpRequest) {
     644          40 :       nsCOMPtr<nsIFileChannel> fileRequest(do_QueryInterface(aRequest));
     645          20 :       if (!fileRequest) {
     646          28 :         nsCOMPtr<nsIWyciwygChannel> wyciwygRequest(do_QueryInterface(aRequest));
     647          14 :         if (!wyciwygRequest) {
     648          28 :           nsCOMPtr<nsIFTPChannel> ftpRequest(do_QueryInterface(aRequest));
     649          14 :           if (!ftpRequest) {
     650          14 :             MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     651             :                    ("SecureUI:%p: OnStateChange: not relevant for sub content\n", this));
     652          14 :             isSubDocumentRelevant = false;
     653             :           }
     654             :         }
     655             :       }
     656             :     }
     657             :   }
     658             : 
     659             :   // This will ignore all resource, chrome, data, file, moz-icon, and anno
     660             :   // protocols. Local resources are treated as trusted.
     661          31 :   if (uri && mIOService) {
     662             :     bool hasFlag;
     663             :     nsresult rv =
     664          50 :       mIOService->URIChainHasFlags(uri,
     665             :                                    nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
     666          50 :                                    &hasFlag);
     667          25 :     if (NS_SUCCEEDED(rv) && hasFlag) {
     668           6 :       isSubDocumentRelevant = false;
     669             :     }
     670             :   }
     671             : 
     672             : #if defined(DEBUG)
     673          62 :   if (aProgressStateFlags & STATE_STOP
     674          47 :       &&
     675          16 :       channel)
     676             :   {
     677          13 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     678             :            ("SecureUI:%p: OnStateChange: seeing STOP with security state: %d\n", this,
     679             :             GetSecurityStateFromSecurityInfoAndRequest(securityInfo, aRequest)
     680             :             ));
     681             :   }
     682             : #endif
     683             : 
     684          31 :   if (aProgressStateFlags & STATE_TRANSFERRING
     685           5 :       &&
     686           5 :       aProgressStateFlags & STATE_IS_REQUEST)
     687             :   {
     688             :     // The listing of a request in mTransferringRequests
     689             :     // means, there has already been data transfered.
     690           5 :     mTransferringRequests.Add(aRequest, fallible);
     691             : 
     692           5 :     return NS_OK;
     693             :   }
     694             : 
     695          26 :   bool requestHasTransferedData = false;
     696             : 
     697          26 :   if (aProgressStateFlags & STATE_STOP
     698          16 :       &&
     699          16 :       aProgressStateFlags & STATE_IS_REQUEST)
     700             :   {
     701          10 :     PLDHashEntryHdr* entry = mTransferringRequests.Search(aRequest);
     702          10 :     if (entry) {
     703           5 :       mTransferringRequests.RemoveEntry(entry);
     704           5 :       requestHasTransferedData = true;
     705             :     }
     706             : 
     707          10 :     if (!requestHasTransferedData) {
     708             :       // Because image loads doesn't support any TRANSFERRING notifications but
     709             :       // only START and STOP we must ask them directly whether content was
     710             :       // transferred.  See bug 432685 for details.
     711             :       nsCOMPtr<nsISecurityInfoProvider> securityInfoProvider =
     712          10 :         do_QueryInterface(aRequest);
     713             :       // Guess true in all failure cases to be safe.  But if we're not
     714             :       // an nsISecurityInfoProvider, then we just haven't transferred
     715             :       // any data.
     716             :       bool hasTransferred;
     717           5 :       requestHasTransferedData =
     718           5 :         securityInfoProvider &&
     719           0 :         (NS_FAILED(securityInfoProvider->GetHasTransferredData(&hasTransferred)) ||
     720           5 :          hasTransferred);
     721             :     }
     722             :   }
     723             : 
     724          26 :   bool allowSecurityStateChange = true;
     725          26 :   if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
     726             :   {
     727             :     // The original consumer (this) is no longer the target of the load.
     728             :     // Ignore any events with this flag, do not allow them to update
     729             :     // our secure UI state.
     730           0 :     allowSecurityStateChange = false;
     731             :   }
     732             : 
     733          26 :   if (aProgressStateFlags & STATE_START
     734          10 :       &&
     735          10 :       aProgressStateFlags & STATE_IS_REQUEST
     736          10 :       &&
     737             :       isToplevelProgress
     738          10 :       &&
     739          10 :       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
     740             :   {
     741             :     int32_t saveSubBroken;
     742             :     int32_t saveSubNo;
     743           6 :     nsCOMPtr<nsIAssociatedContentSecurity> prevContentSecurity;
     744             : 
     745           3 :     int32_t newSubBroken = 0;
     746           3 :     int32_t newSubNo = 0;
     747             : 
     748           3 :     bool inProgress = (mDocumentRequestsInProgress != 0);
     749             : 
     750           3 :     if (allowSecurityStateChange && !inProgress) {
     751           3 :       saveSubBroken = mSubRequestsBrokenSecurity;
     752           3 :       saveSubNo = mSubRequestsNoSecurity;
     753           3 :       prevContentSecurity = do_QueryInterface(mCurrentToplevelSecurityInfo);
     754             :     }
     755             : 
     756           3 :     if (allowSecurityStateChange && !inProgress)
     757             :     {
     758           3 :       MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     759             :              ("SecureUI:%p: OnStateChange: start for toplevel document\n", this
     760             :               ));
     761             : 
     762           3 :       if (prevContentSecurity)
     763             :       {
     764           0 :         MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     765             :                ("SecureUI:%p: OnStateChange: start, saving current sub state\n", this
     766             :                 ));
     767             : 
     768             :         // before resetting our state, let's save information about
     769             :         // sub element loads, so we can restore it later
     770           0 :         prevContentSecurity->SetCountSubRequestsBrokenSecurity(saveSubBroken);
     771           0 :         prevContentSecurity->SetCountSubRequestsNoSecurity(saveSubNo);
     772           0 :         prevContentSecurity->Flush();
     773           0 :         MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI:%p: Saving subs in START to %p as %d,%d\n",
     774             :           this, prevContentSecurity.get(), saveSubBroken, saveSubNo));
     775             :       }
     776             : 
     777           3 :       bool retrieveAssociatedState = false;
     778             : 
     779           3 :       if (securityInfo &&
     780           3 :           (aProgressStateFlags & nsIWebProgressListener::STATE_RESTORING) != 0) {
     781           0 :         retrieveAssociatedState = true;
     782             :       } else {
     783           6 :         nsCOMPtr<nsIWyciwygChannel> wyciwygRequest(do_QueryInterface(aRequest));
     784           3 :         if (wyciwygRequest) {
     785           0 :           retrieveAssociatedState = true;
     786             :         }
     787             :       }
     788             : 
     789           3 :       if (retrieveAssociatedState)
     790             :       {
     791             :         // When restoring from bfcache, we will not get events for the
     792             :         // page's sub elements, so let's load the state of sub elements
     793             :         // from the cache.
     794             : 
     795             :         nsCOMPtr<nsIAssociatedContentSecurity>
     796           0 :           newContentSecurity(do_QueryInterface(securityInfo));
     797             : 
     798           0 :         if (newContentSecurity)
     799             :         {
     800           0 :           MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     801             :                  ("SecureUI:%p: OnStateChange: start, loading old sub state\n", this
     802             :                   ));
     803             : 
     804           0 :           newContentSecurity->GetCountSubRequestsBrokenSecurity(&newSubBroken);
     805           0 :           newContentSecurity->GetCountSubRequestsNoSecurity(&newSubNo);
     806           0 :           MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI:%p: Restoring subs in START from %p to %d,%d\n",
     807             :             this, newContentSecurity.get(), newSubBroken, newSubNo));
     808             :         }
     809             :       }
     810             :       else
     811             :       {
     812             :         // If we don't get OnLocationChange for this top level load later,
     813             :         // it didn't get rendered.  But we reset the state to unknown and
     814             :         // mSubRequests* to zeros.  If we would have left these values after
     815             :         // this top level load stoped, we would override the original top level
     816             :         // load with all zeros and break mixed content state on back and forward.
     817           3 :         mRestoreSubrequests = true;
     818             :       }
     819             :     }
     820             : 
     821           3 :     if (allowSecurityStateChange && !inProgress) {
     822           3 :       ResetStateTracking();
     823           3 :       mSubRequestsBrokenSecurity = newSubBroken;
     824           3 :       mSubRequestsNoSecurity = newSubNo;
     825           3 :       mNewToplevelSecurityStateKnown = false;
     826             :     }
     827             : 
     828             :     // By using a counter, this code also works when the toplevel
     829             :     // document get's redirected, but the STOP request for the
     830             :     // previous toplevel document has not yet have been received.
     831           3 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     832             :            ("SecureUI:%p: OnStateChange: ++mDocumentRequestsInProgress\n", this
     833             :             ));
     834           3 :     ++mDocumentRequestsInProgress;
     835             : 
     836           3 :     return NS_OK;
     837             :   }
     838             : 
     839          23 :   if (aProgressStateFlags & STATE_STOP
     840          16 :       &&
     841          16 :       aProgressStateFlags & STATE_IS_REQUEST
     842          10 :       &&
     843             :       isToplevelProgress
     844          10 :       &&
     845          10 :       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
     846             :   {
     847           6 :     nsCOMPtr<nsISecurityEventSink> temp_ToplevelEventSink;
     848             : 
     849           3 :     if (allowSecurityStateChange) {
     850           3 :       temp_ToplevelEventSink = mToplevelEventSink;
     851             :     }
     852             : 
     853           3 :     if (mDocumentRequestsInProgress <= 0) {
     854             :       // Ignore stop requests unless a document load is in progress
     855             :       // Unfortunately on application start, see some stops without having seen any starts...
     856           0 :       return NS_OK;
     857             :     }
     858             : 
     859           3 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
     860             :            ("SecureUI:%p: OnStateChange: --mDocumentRequestsInProgress\n", this
     861             :             ));
     862             : 
     863           3 :     if (!temp_ToplevelEventSink && channel)
     864             :     {
     865           2 :       if (allowSecurityStateChange)
     866             :       {
     867           2 :         ObtainEventSink(channel, temp_ToplevelEventSink);
     868             :       }
     869             :     }
     870             : 
     871           3 :     bool sinkChanged = false;
     872             :     bool inProgress;
     873           3 :     if (allowSecurityStateChange) {
     874           3 :       sinkChanged = (mToplevelEventSink != temp_ToplevelEventSink);
     875           3 :       mToplevelEventSink = temp_ToplevelEventSink;
     876             :     }
     877           3 :     --mDocumentRequestsInProgress;
     878           3 :     inProgress = mDocumentRequestsInProgress > 0;
     879             : 
     880           3 :     if (allowSecurityStateChange && requestHasTransferedData) {
     881             :       // Data has been transferred for the single toplevel
     882             :       // request. Evaluate the security state.
     883             : 
     884             :       // Do this only when the sink has changed.  We update and notify
     885             :       // the state from OnLacationChange, this is actually redundant.
     886             :       // But when the target sink changes between OnLocationChange and
     887             :       // OnStateChange, we have to fire the notification here (again).
     888             : 
     889           1 :       if (sinkChanged || mOnLocationChangeSeen) {
     890           1 :         EvaluateAndUpdateSecurityState(aRequest, securityInfo, false,
     891           1 :                                        sinkChanged);
     892           1 :         return NS_OK;
     893             :       }
     894             :     }
     895           2 :     mOnLocationChangeSeen = false;
     896             : 
     897           2 :     if (mRestoreSubrequests && !inProgress)
     898             :     {
     899             :       // We get here when there were no OnLocationChange between
     900             :       // OnStateChange(START) and OnStateChange(STOP).  Then the load has not
     901             :       // been rendered but has been retargeted in some other way then by external
     902             :       // app handler.  Restore mSubRequests* members to what the current security
     903             :       // state info holds (it was reset to all zero in OnStateChange(START)
     904             :       // before).
     905             :       nsCOMPtr<nsIAssociatedContentSecurity> currentContentSecurity(
     906           4 :         do_QueryInterface(mCurrentToplevelSecurityInfo));
     907             : 
     908             :       // Drop this indication flag, the restore operation is just being done.
     909           2 :       mRestoreSubrequests = false;
     910             : 
     911             :       // We can do this since the state didn't actually change.
     912           2 :       mNewToplevelSecurityStateKnown = true;
     913             : 
     914           2 :       int32_t subBroken = 0;
     915           2 :       int32_t subNo = 0;
     916             : 
     917           2 :       if (currentContentSecurity)
     918             :       {
     919           0 :         currentContentSecurity->GetCountSubRequestsBrokenSecurity(&subBroken);
     920           0 :         currentContentSecurity->GetCountSubRequestsNoSecurity(&subNo);
     921           0 :         MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI:%p: Restoring subs in STOP from %p to %d,%d\n",
     922             :           this, currentContentSecurity.get(), subBroken, subNo));
     923             :       }
     924             : 
     925           2 :       mSubRequestsBrokenSecurity = subBroken;
     926           2 :       mSubRequestsNoSecurity = subNo;
     927             :     }
     928             : 
     929           2 :     return NS_OK;
     930             :   }
     931             : 
     932          20 :   if (aProgressStateFlags & STATE_STOP
     933          13 :       &&
     934          13 :       aProgressStateFlags & STATE_IS_REQUEST)
     935             :   {
     936           7 :     if (!isSubDocumentRelevant)
     937           5 :       return NS_OK;
     938             : 
     939             :     // if we arrive here, LOAD_DOCUMENT_URI is not set
     940             : 
     941             :     // We only care for the security state of sub requests which have actually transfered data.
     942             : 
     943           2 :     if (allowSecurityStateChange && requestHasTransferedData)
     944             :     {
     945           2 :       UpdateSubrequestMembers(securityInfo, aRequest);
     946             : 
     947             :       // Care for the following scenario:
     948             :       // A new top level document load might have already started,
     949             :       // but the security state of the new top level document might not yet been known.
     950             :       //
     951             :       // At this point, we are learning about the security state of a sub-document.
     952             :       // We must not update the security state based on the sub content,
     953             :       // if the new top level state is not yet known.
     954             :       //
     955             :       // We skip updating the security state in this case.
     956             : 
     957           2 :       if (mNewToplevelSecurityStateKnown) {
     958           2 :         UpdateSecurityState(aRequest, false, false);
     959             :       }
     960             :     }
     961             : 
     962           2 :     return NS_OK;
     963             :   }
     964             : 
     965          13 :   return NS_OK;
     966             : }
     967             : 
     968             : // I'm keeping this as a separate function, in order to simplify the review
     969             : // for bug 412456. We should inline this in a follow up patch.
     970           2 : void nsSecureBrowserUIImpl::ObtainEventSink(nsIChannel *channel,
     971             :                                             nsCOMPtr<nsISecurityEventSink> &sink)
     972             : {
     973           2 :   if (!sink)
     974           2 :     NS_QueryNotificationCallbacks(channel, sink);
     975           2 : }
     976             : 
     977             : void
     978           5 : nsSecureBrowserUIImpl::UpdateSecurityState(nsIRequest* aRequest,
     979             :                                            bool withNewLocation,
     980             :                                            bool withUpdateStatus)
     981             : {
     982           5 :   lockIconState newSecurityState = lis_no_security;
     983           5 :   if (mNewToplevelSecurityState & STATE_IS_SECURE) {
     984             :     // If a subresoure/request was insecure, then we have mixed security.
     985           0 :     if (mSubRequestsBrokenSecurity || mSubRequestsNoSecurity) {
     986           0 :       newSecurityState = lis_mixed_security;
     987             :     } else {
     988           0 :       newSecurityState = lis_high_security;
     989             :     }
     990             :   }
     991             : 
     992           5 :   if (mNewToplevelSecurityState & STATE_IS_BROKEN) {
     993           0 :     newSecurityState = lis_broken_security;
     994             :   }
     995             : 
     996           5 :   mCertUserOverridden =
     997           5 :     mNewToplevelSecurityState & STATE_CERT_USER_OVERRIDDEN;
     998             : 
     999           5 :   MOZ_LOG(gSecureDocLog, LogLevel::Debug,
    1000             :          ("SecureUI:%p: UpdateSecurityState:  old-new  %d - %d\n", this,
    1001             :           mNotifiedSecurityState, newSecurityState));
    1002             : 
    1003           5 :   bool flagsChanged = false;
    1004           5 :   if (mNotifiedSecurityState != newSecurityState) {
    1005             :     // Something changed since the last time.
    1006           0 :     flagsChanged = true;
    1007           0 :     mNotifiedSecurityState = newSecurityState;
    1008             : 
    1009             :     // If we have no security, we also shouldn't have any SSL status.
    1010           0 :     if (newSecurityState == lis_no_security) {
    1011           0 :       mSSLStatus = nullptr;
    1012             :     }
    1013             :   }
    1014             : 
    1015           5 :   if (mNotifiedToplevelIsEV != mNewToplevelIsEV) {
    1016           0 :     flagsChanged = true;
    1017           0 :     mNotifiedToplevelIsEV = mNewToplevelIsEV;
    1018             :   }
    1019             : 
    1020           5 :   if (flagsChanged || withNewLocation || withUpdateStatus) {
    1021           2 :     TellTheWorld(aRequest);
    1022             :   }
    1023           5 : }
    1024             : 
    1025             : void
    1026           2 : nsSecureBrowserUIImpl::TellTheWorld(nsIRequest* aRequest)
    1027             : {
    1028           2 :   uint32_t state = STATE_IS_INSECURE;
    1029           2 :   GetState(&state);
    1030             : 
    1031           2 :   if (mToplevelEventSink) {
    1032           1 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
    1033             :            ("SecureUI:%p: UpdateSecurityState: calling OnSecurityChange\n",
    1034             :             this));
    1035             : 
    1036           1 :     mToplevelEventSink->OnSecurityChange(aRequest, state);
    1037             :   } else {
    1038           1 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
    1039             :            ("SecureUI:%p: UpdateSecurityState: NO mToplevelEventSink!\n",
    1040             :             this));
    1041             : 
    1042             :   }
    1043           2 : }
    1044             : 
    1045             : NS_IMETHODIMP
    1046           2 : nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress,
    1047             :                                         nsIRequest* aRequest,
    1048             :                                         nsIURI* aLocation,
    1049             :                                         uint32_t aFlags)
    1050             : {
    1051           2 :   MOZ_ASSERT(NS_IsMainThread());
    1052           4 :   ReentrancyGuard guard(*this);
    1053             : 
    1054           2 :   MOZ_LOG(gSecureDocLog, LogLevel::Debug,
    1055             :          ("SecureUI:%p: OnLocationChange\n", this));
    1056             : 
    1057           2 :   bool updateIsViewSource = false;
    1058           2 :   bool temp_IsViewSource = false;
    1059           4 :   nsCOMPtr<mozIDOMWindowProxy> window;
    1060             : 
    1061           2 :   if (aLocation)
    1062             :   {
    1063             :     bool vs;
    1064             : 
    1065           2 :     nsresult rv = aLocation->SchemeIs("view-source", &vs);
    1066           2 :     NS_ENSURE_SUCCESS(rv, rv);
    1067             : 
    1068           2 :     if (vs) {
    1069           0 :       MOZ_LOG(gSecureDocLog, LogLevel::Debug,
    1070             :              ("SecureUI:%p: OnLocationChange: view-source\n", this));
    1071             :     }
    1072             : 
    1073           2 :     updateIsViewSource = true;
    1074           2 :     temp_IsViewSource = vs;
    1075             :   }
    1076             : 
    1077           2 :   if (updateIsViewSource) {
    1078           2 :     mIsViewSource = temp_IsViewSource;
    1079             :   }
    1080           2 :   mCurrentURI = aLocation;
    1081           2 :   window = do_QueryReferent(mWindow);
    1082           2 :   MOZ_ASSERT(window, "Window has gone away?!");
    1083             : 
    1084             :   // When |aRequest| is null, basically we don't trust that document. But if
    1085             :   // docshell insists that the document has not changed at all, we will reuse
    1086             :   // the previous security state, no matter what |aRequest| may be.
    1087           2 :   if (aFlags & LOCATION_CHANGE_SAME_DOCUMENT)
    1088           0 :     return NS_OK;
    1089             : 
    1090             :   // The location bar has changed, so we must update the security state.  The
    1091             :   // only concern with doing this here is that a page may transition from being
    1092             :   // reported as completely secure to being reported as partially secure
    1093             :   // (mixed).  This may be confusing for users, and it may bother users who
    1094             :   // like seeing security dialogs.  However, it seems prudent given that page
    1095             :   // loading may never end in some edge cases (perhaps by a site with malicious
    1096             :   // intent).
    1097             : 
    1098           4 :   nsCOMPtr<mozIDOMWindowProxy> windowForProgress;
    1099           2 :   aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress));
    1100             : 
    1101           4 :   nsCOMPtr<nsISupports> securityInfo(ExtractSecurityInfo(aRequest));
    1102             : 
    1103           2 :   if (windowForProgress.get() == window.get()) {
    1104             :     // For toplevel channels, update the security state right away.
    1105           2 :     mOnLocationChangeSeen = true;
    1106           2 :     EvaluateAndUpdateSecurityState(aRequest, securityInfo, true, false);
    1107           2 :     return NS_OK;
    1108             :   }
    1109             : 
    1110             :   // For channels in subdocuments we only update our subrequest state members.
    1111           0 :   UpdateSubrequestMembers(securityInfo, aRequest);
    1112             : 
    1113             :   // Care for the following scenario:
    1114             : 
    1115             :   // A new toplevel document load might have already started, but the security
    1116             :   // state of the new toplevel document might not yet be known.
    1117             :   //
    1118             :   // At this point, we are learning about the security state of a sub-document.
    1119             :   // We must not update the security state based on the sub content, if the new
    1120             :   // top level state is not yet known.
    1121             :   //
    1122             :   // We skip updating the security state in this case.
    1123             : 
    1124           0 :   if (mNewToplevelSecurityStateKnown) {
    1125           0 :     UpdateSecurityState(aRequest, true, false);
    1126             :   }
    1127             : 
    1128           0 :   return NS_OK;
    1129             : }
    1130             : 
    1131             : NS_IMETHODIMP
    1132           0 : nsSecureBrowserUIImpl::OnStatusChange(nsIWebProgress*, nsIRequest*, nsresult,
    1133             :                                       const char16_t*)
    1134             : {
    1135           0 :   MOZ_ASSERT_UNREACHABLE("Should have been excluded in AddProgressListener()");
    1136             :   return NS_OK;
    1137             : }
    1138             : 
    1139             : nsresult
    1140           1 : nsSecureBrowserUIImpl::OnSecurityChange(nsIWebProgress* aWebProgress,
    1141             :                                         nsIRequest* aRequest,
    1142             :                                         uint32_t state)
    1143             : {
    1144           1 :   MOZ_ASSERT(NS_IsMainThread());
    1145             : #if defined(DEBUG)
    1146           2 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
    1147           1 :   if (!channel)
    1148           0 :     return NS_OK;
    1149             : 
    1150           2 :   nsCOMPtr<nsIURI> aURI;
    1151           1 :   channel->GetURI(getter_AddRefs(aURI));
    1152             : 
    1153           1 :   if (aURI) {
    1154           1 :     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
    1155             :            ("SecureUI:%p: OnSecurityChange: (%x) %s\n", this,
    1156             :             state, aURI->GetSpecOrDefault().get()));
    1157             :   }
    1158             : #endif
    1159             : 
    1160           1 :   return NS_OK;
    1161             : }
    1162             : 
    1163             : // nsISSLStatusProvider methods
    1164             : NS_IMETHODIMP
    1165           1 : nsSecureBrowserUIImpl::GetSSLStatus(nsISSLStatus** _result)
    1166             : {
    1167           1 :   NS_ENSURE_ARG_POINTER(_result);
    1168           1 :   MOZ_ASSERT(NS_IsMainThread());
    1169             : 
    1170           1 :   switch (mNotifiedSecurityState)
    1171             :   {
    1172             :     case lis_broken_security:
    1173             :     case lis_mixed_security:
    1174             :     case lis_high_security:
    1175           0 :       break;
    1176             : 
    1177             :     default:
    1178           0 :       MOZ_FALLTHROUGH_ASSERT("if this is reached you must add more entries to the switch");
    1179             :     case lis_no_security:
    1180           1 :       *_result = nullptr;
    1181           1 :       return NS_OK;
    1182             :   }
    1183             : 
    1184           0 :   *_result = mSSLStatus;
    1185           0 :   NS_IF_ADDREF(*_result);
    1186             : 
    1187           0 :   return NS_OK;
    1188           9 : }

Generated by: LCOV version 1.13