LCOV - code coverage report
Current view: directory - uriloader/base - nsDocLoader.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 642 117 18.2 %
Date: 2012-06-02 Functions: 64 19 29.7 %

       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 Communicator client 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
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nspr.h"
      39                 : #include "prlog.h"
      40                 : 
      41                 : #include "nsDocLoader.h"
      42                 : #include "nsCURILoader.h"
      43                 : #include "nsNetUtil.h"
      44                 : #include "nsIHttpChannel.h"
      45                 : #include "nsIWebProgressListener2.h"
      46                 : 
      47                 : #include "nsIServiceManager.h"
      48                 : #include "nsXPIDLString.h"
      49                 : 
      50                 : #include "nsIURL.h"
      51                 : #include "nsCOMPtr.h"
      52                 : #include "nscore.h"
      53                 : #include "nsWeakPtr.h"
      54                 : #include "nsAutoPtr.h"
      55                 : 
      56                 : #include "nsIDOMWindow.h"
      57                 : 
      58                 : #include "nsIStringBundle.h"
      59                 : #include "nsIScriptSecurityManager.h"
      60                 : 
      61                 : #include "nsITransport.h"
      62                 : #include "nsISocketTransport.h"
      63                 : 
      64                 : #include "nsIDOMDocument.h"
      65                 : #include "nsIDocument.h"
      66                 : #include "nsPresContext.h"
      67                 : #include "nsIAsyncVerifyRedirectCallback.h"
      68                 : 
      69                 : static NS_DEFINE_CID(kThisImplCID, NS_THIS_DOCLOADER_IMPL_CID);
      70                 : 
      71                 : #if defined(PR_LOGGING)
      72                 : //
      73                 : // Log module for nsIDocumentLoader logging...
      74                 : //
      75                 : // To enable logging (see prlog.h for full details):
      76                 : //
      77                 : //    set NSPR_LOG_MODULES=DocLoader:5
      78                 : //    set NSPR_LOG_FILE=nspr.log
      79                 : //
      80                 : // this enables PR_LOG_DEBUG level information and places all output in
      81                 : // the file nspr.log
      82                 : //
      83                 : PRLogModuleInfo* gDocLoaderLog = nsnull;
      84                 : #endif /* PR_LOGGING */
      85                 : 
      86                 : 
      87                 : #if defined(DEBUG)
      88               0 : void GetURIStringFromRequest(nsIRequest* request, nsACString &name)
      89                 : {
      90               0 :     if (request)
      91               0 :         request->GetName(name);
      92                 :     else
      93               0 :         name.AssignLiteral("???");
      94               0 : }
      95                 : #endif /* DEBUG */
      96                 : 
      97                 : struct nsStatusInfo : public PRCList
      98                 : {
      99                 :   nsString mStatusMessage;
     100                 :   nsresult mStatusCode;
     101                 :   // Weak mRequest is ok; we'll be told if it decides to go away.
     102                 :   nsIRequest * const mRequest;
     103                 : 
     104               0 :   nsStatusInfo(nsIRequest *aRequest) :
     105               0 :     mRequest(aRequest)
     106                 :   {
     107               0 :     MOZ_COUNT_CTOR(nsStatusInfo);
     108               0 :     PR_INIT_CLIST(this);
     109               0 :   }
     110               0 :   ~nsStatusInfo()
     111               0 :   {
     112               0 :     MOZ_COUNT_DTOR(nsStatusInfo);
     113               0 :     PR_REMOVE_LINK(this);
     114               0 :   }
     115                 : };
     116                 : 
     117                 : struct nsRequestInfo : public PLDHashEntryHdr
     118                 : {
     119               0 :   nsRequestInfo(const void *key)
     120                 :     : mKey(key), mCurrentProgress(0), mMaxProgress(0), mUploading(false)
     121               0 :     , mLastStatus(nsnull)
     122                 :   {
     123               0 :     MOZ_COUNT_CTOR(nsRequestInfo);
     124               0 :   }
     125                 : 
     126               0 :   ~nsRequestInfo()
     127               0 :   {
     128               0 :     MOZ_COUNT_DTOR(nsRequestInfo);
     129               0 :   }
     130                 : 
     131                 :   nsIRequest* Request() {
     132                 :     return static_cast<nsIRequest*>(const_cast<void*>(mKey));
     133                 :   }
     134                 : 
     135                 :   const void* mKey; // Must be first for the pldhash stubs to work
     136                 :   PRInt64 mCurrentProgress;
     137                 :   PRInt64 mMaxProgress;
     138                 :   bool mUploading;
     139                 : 
     140                 :   nsAutoPtr<nsStatusInfo> mLastStatus;
     141                 : };
     142                 : 
     143                 : 
     144                 : static bool
     145               0 : RequestInfoHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
     146                 :                          const void *key)
     147                 : {
     148                 :   // Initialize the entry with placement new
     149               0 :   new (entry) nsRequestInfo(key);
     150               0 :   return true;
     151                 : }
     152                 : 
     153                 : static void
     154               0 : RequestInfoHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
     155                 : {
     156               0 :   nsRequestInfo* info = static_cast<nsRequestInfo *>(entry);
     157               0 :   info->~nsRequestInfo();
     158               0 : }
     159                 : 
     160            1445 : struct nsListenerInfo {
     161            1445 :   nsListenerInfo(nsIWeakReference *aListener, unsigned long aNotifyMask) 
     162                 :     : mWeakListener(aListener),
     163            1445 :       mNotifyMask(aNotifyMask)
     164                 :   {
     165            1445 :   }
     166                 : 
     167                 :   // Weak pointer for the nsIWebProgressListener...
     168                 :   nsWeakPtr mWeakListener;
     169                 : 
     170                 :   // Mask indicating which notifications the listener wants to receive.
     171                 :   unsigned long mNotifyMask;
     172                 : };
     173                 : 
     174                 : 
     175            1404 : nsDocLoader::nsDocLoader()
     176                 :   : mParent(nsnull),
     177                 :     mListenerInfoList(8),
     178                 :     mCurrentSelfProgress(0),
     179                 :     mMaxSelfProgress(0),
     180                 :     mCurrentTotalProgress(0),
     181                 :     mMaxTotalProgress(0),
     182                 :     mCompletedTotalProgress(0),
     183                 :     mIsLoadingDocument(false),
     184                 :     mIsRestoringDocument(false),
     185                 :     mDontFlushLayout(false),
     186            1404 :     mIsFlushingLayout(false)
     187                 : {
     188                 : #if defined(PR_LOGGING)
     189            1404 :   if (nsnull == gDocLoaderLog) {
     190            1404 :       gDocLoaderLog = PR_NewLogModule("DocLoader");
     191                 :   }
     192                 : #endif /* PR_LOGGING */
     193                 : 
     194                 :   static PLDHashTableOps hash_table_ops =
     195                 :   {
     196                 :     PL_DHashAllocTable,
     197                 :     PL_DHashFreeTable,
     198                 :     PL_DHashVoidPtrKeyStub,
     199                 :     PL_DHashMatchEntryStub,
     200                 :     PL_DHashMoveEntryStub,
     201                 :     RequestInfoHashClearEntry,
     202                 :     PL_DHashFinalizeStub,
     203                 :     RequestInfoHashInitEntry
     204                 :   };
     205                 : 
     206            1404 :   if (!PL_DHashTableInit(&mRequestInfoHash, &hash_table_ops, nsnull,
     207            1404 :                          sizeof(nsRequestInfo), 16)) {
     208               0 :     mRequestInfoHash.ops = nsnull;
     209                 :   }
     210                 : 
     211            1404 :   ClearInternalProgress();
     212                 : 
     213            1404 :   PR_INIT_CLIST(&mStatusInfoList);
     214                 : 
     215            1404 :   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
     216                 :          ("DocLoader:%p: created.\n", this));
     217            1404 : }
     218                 : 
     219                 : nsresult
     220               0 : nsDocLoader::SetDocLoaderParent(nsDocLoader *aParent)
     221                 : {
     222               0 :   mParent = aParent;
     223               0 :   return NS_OK; 
     224                 : }
     225                 : 
     226                 : nsresult
     227            1404 : nsDocLoader::Init()
     228                 : {
     229            1404 :   if (!mRequestInfoHash.ops) {
     230               0 :     return NS_ERROR_OUT_OF_MEMORY;
     231                 :   }
     232                 : 
     233            1404 :   nsresult rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), this);
     234            1404 :   if (NS_FAILED(rv)) return rv;
     235                 : 
     236            1404 :   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
     237                 :          ("DocLoader:%p: load group %x.\n", this, mLoadGroup.get()));
     238                 : 
     239            1404 :   return NS_OK;
     240                 : }
     241                 : 
     242            4212 : nsDocLoader::~nsDocLoader()
     243                 : {
     244                 :                 /*
     245                 :                         |ClearWeakReferences()| here is intended to prevent people holding weak references
     246                 :                         from re-entering this destructor since |QueryReferent()| will |AddRef()| me, and the
     247                 :                         subsequent |Release()| will try to destroy me.  At this point there should be only
     248                 :                         weak references remaining (otherwise, we wouldn't be getting destroyed).
     249                 : 
     250                 :                         An alternative would be incrementing our refcount (consider it a compressed flag
     251                 :                         saying "Don't re-destroy.").  I haven't yet decided which is better. [scc]
     252                 :                 */
     253                 :   // XXXbz now that NS_IMPL_RELEASE stabilizes by setting refcount to 1, is
     254                 :   // this needed?
     255            1404 :   ClearWeakReferences();
     256                 : 
     257            1404 :   Destroy();
     258                 : 
     259            1404 :   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG,
     260                 :          ("DocLoader:%p: deleted.\n", this));
     261                 : 
     262            1404 :   if (mRequestInfoHash.ops) {
     263            1404 :     PL_DHashTableFinish(&mRequestInfoHash);
     264                 :   }
     265            5616 : }
     266                 : 
     267                 : 
     268                 : /*
     269                 :  * Implementation of ISupports methods...
     270                 :  */
     271            7182 : NS_IMPL_THREADSAFE_ADDREF(nsDocLoader)
     272            7182 : NS_IMPL_THREADSAFE_RELEASE(nsDocLoader)
     273                 : 
     274            3162 : NS_INTERFACE_MAP_BEGIN(nsDocLoader)
     275            3162 :    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequestObserver)
     276            3123 :    NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
     277            3123 :    NS_INTERFACE_MAP_ENTRY(nsIDocumentLoader)
     278            3123 :    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     279            1719 :    NS_INTERFACE_MAP_ENTRY(nsIWebProgress)
     280             234 :    NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)   
     281             234 :    NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
     282             234 :    NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
     283             234 :    NS_INTERFACE_MAP_ENTRY(nsISecurityEventSink)
     284             234 :    NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
     285             234 :    if (aIID.Equals(kThisImplCID))
     286               0 :      foundInterface = static_cast<nsIDocumentLoader *>(this);
     287                 :    else
     288             234 : NS_INTERFACE_MAP_END
     289                 : 
     290                 : 
     291                 : /*
     292                 :  * Implementation of nsIInterfaceRequestor methods...
     293                 :  */
     294               0 : NS_IMETHODIMP nsDocLoader::GetInterface(const nsIID& aIID, void** aSink)
     295                 : {
     296               0 :   nsresult rv = NS_ERROR_NO_INTERFACE;
     297                 : 
     298               0 :   NS_ENSURE_ARG_POINTER(aSink);
     299                 : 
     300               0 :   if(aIID.Equals(NS_GET_IID(nsILoadGroup))) {
     301               0 :     *aSink = mLoadGroup;
     302               0 :     NS_IF_ADDREF((nsISupports*)*aSink);
     303               0 :     rv = NS_OK;
     304                 :   } else {
     305               0 :     rv = QueryInterface(aIID, aSink);
     306                 :   }
     307                 : 
     308               0 :   return rv;
     309                 : }
     310                 : 
     311                 : /* static */
     312                 : already_AddRefed<nsDocLoader>
     313               0 : nsDocLoader::GetAsDocLoader(nsISupports* aSupports)
     314                 : {
     315               0 :   if (!aSupports) {
     316               0 :     return nsnull;
     317                 :   }
     318                 :   
     319                 :   nsDocLoader* ptr;
     320               0 :   CallQueryInterface(aSupports, &ptr);
     321               0 :   return ptr;
     322                 : }
     323                 : 
     324                 : /* static */
     325                 : nsresult
     326               0 : nsDocLoader::AddDocLoaderAsChildOfRoot(nsDocLoader* aDocLoader)
     327                 : {
     328                 :   nsresult rv;
     329                 :   nsCOMPtr<nsIDocumentLoader> docLoaderService =
     330               0 :     do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID, &rv);
     331               0 :   NS_ENSURE_SUCCESS(rv, rv);
     332                 : 
     333               0 :   nsRefPtr<nsDocLoader> rootDocLoader = GetAsDocLoader(docLoaderService);
     334               0 :   NS_ENSURE_TRUE(rootDocLoader, NS_ERROR_UNEXPECTED);
     335                 : 
     336               0 :   return rootDocLoader->AddChildLoader(aDocLoader);
     337                 : }
     338                 : 
     339                 : NS_IMETHODIMP
     340            1404 : nsDocLoader::Stop(void)
     341                 : {
     342            1404 :   nsresult rv = NS_OK;
     343                 :   PRInt32 count, i;
     344                 : 
     345            1404 :   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
     346                 :          ("DocLoader:%p: Stop() called\n", this));
     347                 : 
     348            1404 :   count = mChildList.Count();
     349                 : 
     350            2808 :   nsCOMPtr<nsIDocumentLoader> loader;
     351            1404 :   for (i=0; i < count; i++) {
     352               0 :     loader = ChildAt(i);
     353                 : 
     354               0 :     if (loader) {
     355               0 :       (void) loader->Stop();
     356                 :     }
     357                 :   }
     358                 : 
     359            1404 :   if (mLoadGroup)
     360            1404 :     rv = mLoadGroup->Cancel(NS_BINDING_ABORTED);
     361                 : 
     362                 :   // Don't report that we're flushing layout so IsBusy returns false after a
     363                 :   // Stop call.
     364            1404 :   mIsFlushingLayout = false;
     365                 : 
     366                 :   // Clear out mChildrenInOnload.  We want to make sure to fire our
     367                 :   // onload at this point, and there's no issue with mChildrenInOnload
     368                 :   // after this, since mDocumentRequest will be null after the
     369                 :   // DocLoaderIsEmpty() call.
     370            1404 :   mChildrenInOnload.Clear();
     371                 : 
     372                 :   // Make sure to call DocLoaderIsEmpty now so that we reset mDocumentRequest,
     373                 :   // etc, as needed.  We could be getting into here from a subframe onload, in
     374                 :   // which case the call to DocLoaderIsEmpty() is coming but hasn't quite
     375                 :   // happened yet, Canceling the loadgroup did nothing (because it was already
     376                 :   // empty), and we're about to start a new load (which is what triggered this
     377                 :   // Stop() call).
     378                 : 
     379                 :   // XXXbz If the child frame loadgroups were requests in mLoadgroup, I suspect
     380                 :   // we wouldn't need the call here....
     381                 : 
     382            1404 :   NS_ASSERTION(!IsBusy(), "Shouldn't be busy here");
     383            1404 :   DocLoaderIsEmpty(false);
     384                 :   
     385            1404 :   return rv;
     386                 : }       
     387                 : 
     388                 : 
     389                 : bool
     390            1404 : nsDocLoader::IsBusy()
     391                 : {
     392                 :   nsresult rv;
     393                 : 
     394                 :   //
     395                 :   // A document loader is busy if either:
     396                 :   //
     397                 :   //   1. One of its children is in the middle of an onload handler.  Note that
     398                 :   //      the handler may have already removed this child from mChildList!
     399                 :   //   2. It is currently loading a document and either has parts of it still
     400                 :   //      loading, or has a busy child docloader.
     401                 :   //   3. It's currently flushing layout in DocLoaderIsEmpty().
     402                 :   //
     403                 : 
     404            1404 :   if (mChildrenInOnload.Count() || mIsFlushingLayout) {
     405               0 :     return true;
     406                 :   }
     407                 : 
     408                 :   /* Is this document loader busy? */
     409            1404 :   if (!mIsLoadingDocument) {
     410            1404 :     return false;
     411                 :   }
     412                 :   
     413                 :   bool busy;
     414               0 :   rv = mLoadGroup->IsPending(&busy);
     415               0 :   if (NS_FAILED(rv)) {
     416               0 :     return false;
     417                 :   }
     418               0 :   if (busy) {
     419               0 :     return true;
     420                 :   }
     421                 : 
     422                 :   /* check its child document loaders... */
     423                 :   PRInt32 count, i;
     424                 : 
     425               0 :   count = mChildList.Count();
     426                 : 
     427               0 :   for (i=0; i < count; i++) {
     428               0 :     nsIDocumentLoader* loader = ChildAt(i);
     429                 : 
     430                 :     // This is a safe cast, because we only put nsDocLoader objects into the
     431                 :     // array
     432               0 :     if (loader && static_cast<nsDocLoader*>(loader)->IsBusy())
     433               0 :       return true;
     434                 :   }
     435                 : 
     436               0 :   return false;
     437                 : }
     438                 : 
     439                 : NS_IMETHODIMP
     440               0 : nsDocLoader::GetContainer(nsISupports** aResult)
     441                 : {
     442               0 :    NS_ADDREF(*aResult = static_cast<nsIDocumentLoader*>(this));
     443                 : 
     444               0 :    return NS_OK;
     445                 : }
     446                 : 
     447                 : NS_IMETHODIMP
     448               0 : nsDocLoader::GetLoadGroup(nsILoadGroup** aResult)
     449                 : {
     450               0 :   nsresult rv = NS_OK;
     451                 : 
     452               0 :   if (nsnull == aResult) {
     453               0 :     rv = NS_ERROR_NULL_POINTER;
     454                 :   } else {
     455               0 :     *aResult = mLoadGroup;
     456               0 :     NS_IF_ADDREF(*aResult);
     457                 :   }
     458               0 :   return rv;
     459                 : }
     460                 : 
     461                 : void
     462            1404 : nsDocLoader::Destroy()
     463                 : {
     464            1404 :   Stop();
     465                 : 
     466                 :   // Remove the document loader from the parent list of loaders...
     467            1404 :   if (mParent) 
     468                 :   {
     469               0 :     mParent->RemoveChildLoader(this);
     470                 :   }
     471                 : 
     472                 :   // Release all the information about network requests...
     473            1404 :   ClearRequestInfoHash();
     474                 : 
     475                 :   // Release all the information about registered listeners...
     476            1404 :   PRInt32 count = mListenerInfoList.Count();
     477            2848 :   for(PRInt32 i = 0; i < count; i++) {
     478                 :     nsListenerInfo *info =
     479            1444 :       static_cast<nsListenerInfo*>(mListenerInfoList.ElementAt(i));
     480                 : 
     481            1444 :     delete info;
     482                 :   }
     483                 : 
     484            1404 :   mListenerInfoList.Clear();
     485            1404 :   mListenerInfoList.Compact();
     486                 : 
     487            1404 :   mDocumentRequest = 0;
     488                 : 
     489            1404 :   if (mLoadGroup)
     490            1404 :     mLoadGroup->SetGroupObserver(nsnull);
     491                 : 
     492            1404 :   DestroyChildren();
     493            1404 : }
     494                 : 
     495                 : void
     496            1404 : nsDocLoader::DestroyChildren()
     497                 : {
     498                 :   PRInt32 i, count;
     499                 :   
     500            1404 :   count = mChildList.Count();
     501                 :   // if the doc loader still has children...we need to enumerate the
     502                 :   // children and make them null out their back ptr to the parent doc
     503                 :   // loader
     504            1404 :   for (i=0; i < count; i++)
     505                 :   {
     506               0 :     nsIDocumentLoader* loader = ChildAt(i);
     507                 : 
     508               0 :     if (loader) {
     509                 :       // This is a safe cast, as we only put nsDocLoader objects into the
     510                 :       // array
     511               0 :       static_cast<nsDocLoader*>(loader)->SetDocLoaderParent(nsnull);
     512                 :     }
     513                 :   }
     514            1404 :   mChildList.Clear();
     515            1404 : }
     516                 : 
     517                 : NS_IMETHODIMP
     518               0 : nsDocLoader::OnStartRequest(nsIRequest *request, nsISupports *aCtxt)
     519                 : {
     520                 :   // called each time a request is added to the group.
     521                 : 
     522                 : #ifdef PR_LOGGING
     523               0 :   if (PR_LOG_TEST(gDocLoaderLog, PR_LOG_DEBUG)) {
     524               0 :     nsCAutoString name;
     525               0 :     request->GetName(name);
     526                 : 
     527               0 :     PRUint32 count = 0;
     528               0 :     if (mLoadGroup)
     529               0 :       mLoadGroup->GetActiveCount(&count);
     530                 : 
     531               0 :     PR_LOG(gDocLoaderLog, PR_LOG_DEBUG,
     532                 :            ("DocLoader:%p: OnStartRequest[%p](%s) mIsLoadingDocument=%s, %u active URLs",
     533                 :             this, request, name.get(),
     534                 :             (mIsLoadingDocument ? "true" : "false"),
     535                 :             count));
     536                 :   }
     537                 : #endif /* PR_LOGGING */
     538               0 :   bool bJustStartedLoading = false;
     539                 : 
     540               0 :   nsLoadFlags loadFlags = 0;
     541               0 :   request->GetLoadFlags(&loadFlags);
     542                 : 
     543               0 :   if (!mIsLoadingDocument && (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)) {
     544               0 :       bJustStartedLoading = true;
     545               0 :       mIsLoadingDocument = true;
     546               0 :       ClearInternalProgress(); // only clear our progress if we are starting a new load....
     547                 :   }
     548                 : 
     549                 :   //
     550                 :   // Create a new nsRequestInfo for the request that is starting to
     551                 :   // load...
     552                 :   //
     553               0 :   AddRequestInfo(request);
     554                 : 
     555                 :   //
     556                 :   // Only fire a doStartDocumentLoad(...) if the document loader
     557                 :   // has initiated a load...  Otherwise, this notification has
     558                 :   // resulted from a request being added to the load group.
     559                 :   //
     560               0 :   if (mIsLoadingDocument) {
     561               0 :     if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
     562                 :       //
     563                 :       // Make sure that the document channel is null at this point...
     564                 :       // (unless its been redirected)
     565                 :       //
     566               0 :       NS_ASSERTION((loadFlags & nsIChannel::LOAD_REPLACE) ||
     567                 :                    !(mDocumentRequest.get()),
     568                 :                    "Overwriting an existing document channel!");
     569                 : 
     570                 :       // This request is associated with the entire document...
     571               0 :       mDocumentRequest = request;
     572               0 :       mLoadGroup->SetDefaultLoadRequest(request); 
     573                 : 
     574                 :       // Only fire the start document load notification for the first
     575                 :       // document URI...  Do not fire it again for redirections
     576                 :       //
     577               0 :       if (bJustStartedLoading) {
     578                 :         // Update the progress status state
     579               0 :         mProgressStateFlags = nsIWebProgressListener::STATE_START;
     580                 : 
     581                 :         // Fire the start document load notification
     582               0 :         doStartDocumentLoad();
     583               0 :         return NS_OK;
     584                 :       }
     585                 :     } 
     586                 :   }
     587                 : 
     588               0 :   NS_ASSERTION(!mIsLoadingDocument || mDocumentRequest,
     589                 :                "mDocumentRequest MUST be set for the duration of a page load!");
     590                 : 
     591               0 :   doStartURLLoad(request);
     592                 : 
     593               0 :   return NS_OK;
     594                 : }
     595                 : 
     596                 : NS_IMETHODIMP
     597               0 : nsDocLoader::OnStopRequest(nsIRequest *aRequest, 
     598                 :                            nsISupports *aCtxt,
     599                 :                            nsresult aStatus)
     600                 : {
     601               0 :   nsresult rv = NS_OK;
     602                 : 
     603                 : #ifdef PR_LOGGING
     604               0 :   if (PR_LOG_TEST(gDocLoaderLog, PR_LOG_DEBUG)) {
     605               0 :     nsCAutoString name;
     606               0 :     aRequest->GetName(name);
     607                 : 
     608               0 :     PRUint32 count = 0;
     609               0 :     if (mLoadGroup)
     610               0 :       mLoadGroup->GetActiveCount(&count);
     611                 : 
     612               0 :     PR_LOG(gDocLoaderLog, PR_LOG_DEBUG,
     613                 :            ("DocLoader:%p: OnStopRequest[%p](%s) status=%x mIsLoadingDocument=%s, %u active URLs",
     614                 :            this, aRequest, name.get(),
     615                 :            aStatus, (mIsLoadingDocument ? "true" : "false"),
     616                 :            count));
     617                 :   }
     618                 : #endif
     619                 : 
     620               0 :   bool bFireTransferring = false;
     621                 : 
     622                 :   //
     623                 :   // Set the Maximum progress to the same value as the current progress.
     624                 :   // Since the URI has finished loading, all the data is there.  Also,
     625                 :   // this will allow a more accurate estimation of the max progress (in case
     626                 :   // the old value was unknown ie. -1)
     627                 :   //
     628               0 :   nsRequestInfo *info = GetRequestInfo(aRequest);
     629               0 :   if (info) {
     630                 :     // Null out mLastStatus now so we don't find it when looking for
     631                 :     // status from now on.  This destroys the nsStatusInfo and hence
     632                 :     // removes it from our list.
     633               0 :     info->mLastStatus = nsnull;
     634                 : 
     635               0 :     PRInt64 oldMax = info->mMaxProgress;
     636                 : 
     637               0 :     info->mMaxProgress = info->mCurrentProgress;
     638                 :     
     639                 :     //
     640                 :     // If a request whose content-length was previously unknown has just
     641                 :     // finished loading, then use this new data to try to calculate a
     642                 :     // mMaxSelfProgress...
     643                 :     //
     644               0 :     if ((oldMax < PRInt64(0)) && (mMaxSelfProgress < PRInt64(0))) {
     645               0 :       mMaxSelfProgress = CalculateMaxProgress();
     646                 :     }
     647                 : 
     648                 :     // As we know the total progress of this request now, save it to be part
     649                 :     // of CalculateMaxProgress() result. We need to remove the info from the
     650                 :     // hash, see bug 480713.
     651               0 :     mCompletedTotalProgress += info->mMaxProgress;
     652                 :     
     653                 :     //
     654                 :     // Determine whether a STATE_TRANSFERRING notification should be
     655                 :     // 'synthesized'.
     656                 :     //
     657                 :     // If nsRequestInfo::mMaxProgress (as stored in oldMax) and
     658                 :     // nsRequestInfo::mCurrentProgress are both 0, then the
     659                 :     // STATE_TRANSFERRING notification has not been fired yet...
     660                 :     //
     661               0 :     if ((oldMax == LL_ZERO) && (info->mCurrentProgress == LL_ZERO)) {
     662               0 :       nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
     663                 : 
     664                 :       // Only fire a TRANSFERRING notification if the request is also a
     665                 :       // channel -- data transfer requires a nsIChannel!
     666                 :       //
     667               0 :       if (channel) {
     668               0 :         if (NS_SUCCEEDED(aStatus)) {
     669               0 :           bFireTransferring = true;
     670                 :         }
     671                 :         //
     672                 :         // If the request failed (for any reason other than being
     673                 :         // redirected or retargeted), the TRANSFERRING notification can
     674                 :         // still be fired if a HTTP connection was established to a server.
     675                 :         //
     676               0 :         else if (aStatus != NS_BINDING_REDIRECTED &&
     677                 :                  aStatus != NS_BINDING_RETARGETED) {
     678                 :           //
     679                 :           // Only if the load has been targeted (see bug 268483)...
     680                 :           //
     681                 :           PRUint32 lf;
     682               0 :           channel->GetLoadFlags(&lf);
     683               0 :           if (lf & nsIChannel::LOAD_TARGETED) {
     684               0 :             nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
     685               0 :             if (httpChannel) {
     686                 :               PRUint32 responseCode;
     687               0 :               rv = httpChannel->GetResponseStatus(&responseCode);
     688               0 :               if (NS_SUCCEEDED(rv)) {
     689                 :                 //
     690                 :                 // A valid server status indicates that a connection was
     691                 :                 // established to the server... So, fire the notification
     692                 :                 // even though a failure occurred later...
     693                 :                 //
     694               0 :                 bFireTransferring = true;
     695                 :               }
     696                 :             }
     697                 :           }
     698                 :         }
     699                 :       }
     700                 :     }
     701                 :   }
     702                 : 
     703               0 :   if (bFireTransferring) {
     704                 :     // Send a STATE_TRANSFERRING notification for the request.
     705                 :     PRInt32 flags;
     706                 :     
     707                 :     flags = nsIWebProgressListener::STATE_TRANSFERRING |
     708               0 :             nsIWebProgressListener::STATE_IS_REQUEST;
     709                 :     //
     710                 :     // Move the WebProgress into the STATE_TRANSFERRING state if necessary...
     711                 :     //
     712               0 :     if (mProgressStateFlags & nsIWebProgressListener::STATE_START) {
     713               0 :       mProgressStateFlags = nsIWebProgressListener::STATE_TRANSFERRING;
     714                 : 
     715                 :       // Send STATE_TRANSFERRING for the document too...
     716               0 :       flags |= nsIWebProgressListener::STATE_IS_DOCUMENT;
     717                 :     }
     718                 : 
     719               0 :     FireOnStateChange(this, aRequest, flags, NS_OK);
     720                 :   }
     721                 : 
     722                 :   //
     723                 :   // Fire the OnStateChange(...) notification for stop request
     724                 :   //
     725               0 :   doStopURLLoad(aRequest, aStatus);
     726                 :   
     727                 :   // Clear this request out of the hash to avoid bypass of FireOnStateChange
     728                 :   // when address of the request is reused.
     729               0 :   RemoveRequestInfo(aRequest);
     730                 :   
     731                 :   //
     732                 :   // Only fire the DocLoaderIsEmpty(...) if the document loader has initiated a
     733                 :   // load.  This will handle removing the request from our hashtable as needed.
     734                 :   //
     735               0 :   if (mIsLoadingDocument) {
     736               0 :     DocLoaderIsEmpty(true);
     737                 :   }
     738                 :   
     739               0 :   return NS_OK;
     740                 : }
     741                 : 
     742                 : 
     743               0 : nsresult nsDocLoader::RemoveChildLoader(nsDocLoader* aChild)
     744                 : {
     745               0 :   nsresult rv = mChildList.RemoveElement(aChild) ? NS_OK : NS_ERROR_FAILURE;
     746               0 :   if (NS_SUCCEEDED(rv)) {
     747               0 :     aChild->SetDocLoaderParent(nsnull);
     748                 :   }
     749               0 :   return rv;
     750                 : }
     751                 : 
     752               0 : nsresult nsDocLoader::AddChildLoader(nsDocLoader* aChild)
     753                 : {
     754               0 :   nsresult rv = mChildList.AppendElement(aChild) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     755               0 :   if (NS_SUCCEEDED(rv)) {
     756               0 :     aChild->SetDocLoaderParent(this);
     757                 :   }
     758               0 :   return rv;
     759                 : }
     760                 : 
     761               0 : NS_IMETHODIMP nsDocLoader::GetDocumentChannel(nsIChannel ** aChannel)
     762                 : {
     763               0 :   if (!mDocumentRequest) {
     764               0 :     *aChannel = nsnull;
     765               0 :     return NS_OK;
     766                 :   }
     767                 :   
     768               0 :   return CallQueryInterface(mDocumentRequest, aChannel);
     769                 : }
     770                 : 
     771                 : 
     772            1404 : void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout)
     773                 : {
     774            1404 :   if (mIsLoadingDocument) {
     775                 :     /* In the unimagineably rude circumstance that onload event handlers
     776                 :        triggered by this function actually kill the window ... ok, it's
     777                 :        not unimagineable; it's happened ... this deathgrip keeps this object
     778                 :        alive long enough to survive this function call. */
     779               0 :     nsCOMPtr<nsIDocumentLoader> kungFuDeathGrip(this);
     780                 : 
     781                 :     // Don't flush layout if we're still busy.
     782               0 :     if (IsBusy()) {
     783                 :       return;
     784                 :     }
     785                 : 
     786               0 :     NS_ASSERTION(!mIsFlushingLayout, "Someone screwed up");
     787                 : 
     788                 :     // The load group for this DocumentLoader is idle.  Flush if we need to.
     789               0 :     if (aFlushLayout && !mDontFlushLayout) {
     790               0 :       nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(GetAsSupports(this));
     791               0 :       nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
     792               0 :       if (doc) {
     793                 :         // We start loads from style resolution, so we need to flush out style
     794                 :         // no matter what.  If we have user fonts, we also need to flush layout,
     795                 :         // since the reflow is what starts font loads.
     796               0 :         mozFlushType flushType = Flush_Style;
     797               0 :         nsIPresShell* shell = doc->GetShell();
     798               0 :         if (shell) {
     799                 :           // Be safe in case this presshell is in teardown now
     800               0 :           nsPresContext* presContext = shell->GetPresContext();
     801               0 :           if (presContext && presContext->GetUserFontSet()) {
     802               0 :             flushType = Flush_Layout;
     803                 :           }
     804                 :         }
     805               0 :         mDontFlushLayout = mIsFlushingLayout = true;
     806               0 :         doc->FlushPendingNotifications(flushType);
     807               0 :         mDontFlushLayout = mIsFlushingLayout = false;
     808                 :       }
     809                 :     }
     810                 : 
     811                 :     // And now check whether we're really busy; that might have changed with
     812                 :     // the layout flush.
     813               0 :     if (!IsBusy()) {
     814                 :       // Clear out our request info hash, now that our load really is done and
     815                 :       // we don't need it anymore to CalculateMaxProgress().
     816               0 :       ClearInternalProgress();
     817                 : 
     818               0 :       PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
     819                 :              ("DocLoader:%p: Is now idle...\n", this));
     820                 : 
     821               0 :       nsCOMPtr<nsIRequest> docRequest = mDocumentRequest;
     822                 : 
     823               0 :       NS_ASSERTION(mDocumentRequest, "No Document Request!");
     824               0 :       mDocumentRequest = 0;
     825               0 :       mIsLoadingDocument = false;
     826                 : 
     827                 :       // Update the progress status state - the document is done
     828               0 :       mProgressStateFlags = nsIWebProgressListener::STATE_STOP;
     829                 : 
     830                 : 
     831               0 :       nsresult loadGroupStatus = NS_OK; 
     832               0 :       mLoadGroup->GetStatus(&loadGroupStatus);
     833                 : 
     834                 :       // 
     835                 :       // New code to break the circular reference between 
     836                 :       // the load group and the docloader... 
     837                 :       // 
     838               0 :       mLoadGroup->SetDefaultLoadRequest(nsnull); 
     839                 : 
     840                 :       // Take a ref to our parent now so that we can call DocLoaderIsEmpty() on
     841                 :       // it even if our onload handler removes us from the docloader tree.
     842               0 :       nsRefPtr<nsDocLoader> parent = mParent;
     843                 : 
     844                 :       // Note that if calling ChildEnteringOnload() on the parent returns false
     845                 :       // then calling our onload handler is not safe.  That can only happen on
     846                 :       // OOM, so that's ok.
     847               0 :       if (!parent || parent->ChildEnteringOnload(this)) {
     848                 :         // Do nothing with our state after firing the
     849                 :         // OnEndDocumentLoad(...). The document loader may be loading a *new*
     850                 :         // document - if LoadDocument() was called from a handler!
     851                 :         //
     852               0 :         doStopDocumentLoad(docRequest, loadGroupStatus);
     853                 : 
     854               0 :         if (parent) {
     855               0 :           parent->ChildDoneWithOnload(this);
     856                 :         }
     857                 :       }
     858                 :     }
     859                 :   }
     860                 : }
     861                 : 
     862               0 : void nsDocLoader::doStartDocumentLoad(void)
     863                 : {
     864                 : 
     865                 : #if defined(DEBUG)
     866               0 :   nsCAutoString buffer;
     867                 : 
     868               0 :   GetURIStringFromRequest(mDocumentRequest, buffer);
     869               0 :   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
     870                 :          ("DocLoader:%p: ++ Firing OnStateChange for start document load (...)."
     871                 :           "\tURI: %s \n",
     872                 :           this, buffer.get()));
     873                 : #endif /* DEBUG */
     874                 : 
     875                 :   // Fire an OnStatus(...) notification STATE_START.  This indicates
     876                 :   // that the document represented by mDocumentRequest has started to
     877                 :   // load...
     878                 :   FireOnStateChange(this,
     879                 :                     mDocumentRequest,
     880                 :                     nsIWebProgressListener::STATE_START |
     881                 :                     nsIWebProgressListener::STATE_IS_DOCUMENT |
     882                 :                     nsIWebProgressListener::STATE_IS_REQUEST |
     883                 :                     nsIWebProgressListener::STATE_IS_WINDOW |
     884                 :                     nsIWebProgressListener::STATE_IS_NETWORK,
     885               0 :                     NS_OK);
     886               0 : }
     887                 : 
     888               0 : void nsDocLoader::doStartURLLoad(nsIRequest *request)
     889                 : {
     890                 : #if defined(DEBUG)
     891               0 :   nsCAutoString buffer;
     892                 : 
     893               0 :   GetURIStringFromRequest(request, buffer);
     894               0 :     PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
     895                 :           ("DocLoader:%p: ++ Firing OnStateChange start url load (...)."
     896                 :            "\tURI: %s\n",
     897                 :             this, buffer.get()));
     898                 : #endif /* DEBUG */
     899                 : 
     900                 :   FireOnStateChange(this,
     901                 :                     request,
     902                 :                     nsIWebProgressListener::STATE_START |
     903                 :                     nsIWebProgressListener::STATE_IS_REQUEST,
     904               0 :                     NS_OK);
     905               0 : }
     906                 : 
     907               0 : void nsDocLoader::doStopURLLoad(nsIRequest *request, nsresult aStatus)
     908                 : {
     909                 : #if defined(DEBUG)
     910               0 :   nsCAutoString buffer;
     911                 : 
     912               0 :   GetURIStringFromRequest(request, buffer);
     913               0 :     PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
     914                 :           ("DocLoader:%p: ++ Firing OnStateChange for end url load (...)."
     915                 :            "\tURI: %s status=%x\n",
     916                 :             this, buffer.get(), aStatus));
     917                 : #endif /* DEBUG */
     918                 : 
     919                 :   FireOnStateChange(this,
     920                 :                     request,
     921                 :                     nsIWebProgressListener::STATE_STOP |
     922                 :                     nsIWebProgressListener::STATE_IS_REQUEST,
     923               0 :                     aStatus);
     924                 : 
     925                 :   // Fire a status change message for the most recent unfinished
     926                 :   // request to make sure that the displayed status is not outdated.
     927               0 :   if (!PR_CLIST_IS_EMPTY(&mStatusInfoList)) {
     928                 :     nsStatusInfo* statusInfo =
     929               0 :       static_cast<nsStatusInfo*>(PR_LIST_HEAD(&mStatusInfoList));
     930                 :     FireOnStatusChange(this, statusInfo->mRequest,
     931                 :                        statusInfo->mStatusCode,
     932               0 :                        statusInfo->mStatusMessage.get());
     933                 :   }
     934               0 : }
     935                 : 
     936               0 : void nsDocLoader::doStopDocumentLoad(nsIRequest *request,
     937                 :                                          nsresult aStatus)
     938                 : {
     939                 : #if defined(DEBUG)
     940               0 :   nsCAutoString buffer;
     941                 : 
     942               0 :   GetURIStringFromRequest(request, buffer);
     943               0 :   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
     944                 :          ("DocLoader:%p: ++ Firing OnStateChange for end document load (...)."
     945                 :          "\tURI: %s Status=%x\n",
     946                 :           this, buffer.get(), aStatus));
     947                 : #endif /* DEBUG */
     948                 : 
     949                 :   // Firing STATE_STOP|STATE_IS_DOCUMENT will fire onload handlers.
     950                 :   // Grab our parent chain before doing that so we can still dispatch
     951                 :   // STATE_STOP|STATE_IS_WINDW_STATE_IS_NETWORK to them all, even if
     952                 :   // the onload handlers rearrange the docshell tree.
     953               0 :   WebProgressList list;
     954               0 :   GatherAncestorWebProgresses(list);
     955                 :   
     956                 :   //
     957                 :   // Fire an OnStateChange(...) notification indicating the the
     958                 :   // current document has finished loading...
     959                 :   //
     960                 :   PRInt32 flags = nsIWebProgressListener::STATE_STOP |
     961               0 :                   nsIWebProgressListener::STATE_IS_DOCUMENT;
     962               0 :   for (PRUint32 i = 0; i < list.Length(); ++i) {
     963               0 :     list[i]->DoFireOnStateChange(this, request, flags, aStatus);
     964                 :   }
     965                 : 
     966                 :   //
     967                 :   // Fire a final OnStateChange(...) notification indicating the the
     968                 :   // current document has finished loading...
     969                 :   //
     970                 :   flags = nsIWebProgressListener::STATE_STOP |
     971                 :           nsIWebProgressListener::STATE_IS_WINDOW |
     972               0 :           nsIWebProgressListener::STATE_IS_NETWORK;
     973               0 :   for (PRUint32 i = 0; i < list.Length(); ++i) {
     974               0 :     list[i]->DoFireOnStateChange(this, request, flags, aStatus);
     975                 :   }
     976               0 : }
     977                 : 
     978                 : ////////////////////////////////////////////////////////////////////////////////////
     979                 : // The following section contains support for nsIWebProgress and related stuff
     980                 : ////////////////////////////////////////////////////////////////////////////////////
     981                 : 
     982                 : NS_IMETHODIMP
     983            1445 : nsDocLoader::AddProgressListener(nsIWebProgressListener *aListener,
     984                 :                                      PRUint32 aNotifyMask)
     985                 : {
     986                 :   nsresult rv;
     987                 : 
     988            1445 :   nsListenerInfo* info = GetListenerInfo(aListener);
     989            1445 :   if (info) {
     990                 :     // The listener is already registered!
     991               0 :     return NS_ERROR_FAILURE;
     992                 :   }
     993                 : 
     994            2890 :   nsWeakPtr listener = do_GetWeakReference(aListener);
     995            1445 :   if (!listener) {
     996               0 :     return NS_ERROR_INVALID_ARG;
     997                 :   }
     998                 : 
     999            2890 :   info = new nsListenerInfo(listener, aNotifyMask);
    1000            1445 :   if (!info) {
    1001               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1002                 :   }
    1003                 : 
    1004            1445 :   rv = mListenerInfoList.AppendElement(info) ? NS_OK : NS_ERROR_FAILURE;
    1005            1445 :   return rv;
    1006                 : }
    1007                 : 
    1008                 : NS_IMETHODIMP
    1009               1 : nsDocLoader::RemoveProgressListener(nsIWebProgressListener *aListener)
    1010                 : {
    1011                 :   nsresult rv;
    1012                 : 
    1013               1 :   nsListenerInfo* info = GetListenerInfo(aListener);
    1014               1 :   if (info) {
    1015               1 :     rv = mListenerInfoList.RemoveElement(info) ? NS_OK : NS_ERROR_FAILURE;
    1016               1 :     delete info;
    1017                 :   } else {
    1018                 :     // The listener is not registered!
    1019               0 :     rv = NS_ERROR_FAILURE;
    1020                 :   }
    1021               1 :   return rv;
    1022                 : }
    1023                 : 
    1024                 : NS_IMETHODIMP
    1025               0 : nsDocLoader::GetDOMWindow(nsIDOMWindow **aResult)
    1026                 : {
    1027               0 :   return CallGetInterface(this, aResult);
    1028                 : }
    1029                 : 
    1030                 : NS_IMETHODIMP
    1031               0 : nsDocLoader::GetIsLoadingDocument(bool *aIsLoadingDocument)
    1032                 : {
    1033               0 :   *aIsLoadingDocument = mIsLoadingDocument;
    1034                 : 
    1035               0 :   return NS_OK;
    1036                 : }
    1037                 : 
    1038               0 : PRInt64 nsDocLoader::GetMaxTotalProgress()
    1039                 : {
    1040               0 :   PRInt64 newMaxTotal = 0;
    1041                 : 
    1042               0 :   PRInt32 count = mChildList.Count();
    1043               0 :   nsCOMPtr<nsIWebProgress> webProgress;
    1044               0 :   for (PRInt32 i=0; i < count; i++) 
    1045                 :   {
    1046               0 :     PRInt64 individualProgress = 0;
    1047               0 :     nsIDocumentLoader* docloader = ChildAt(i);
    1048               0 :     if (docloader)
    1049                 :     {
    1050                 :       // Cast is safe since all children are nsDocLoader too
    1051               0 :       individualProgress = ((nsDocLoader *) docloader)->GetMaxTotalProgress();
    1052                 :     }
    1053               0 :     if (individualProgress < PRInt64(0)) // if one of the elements doesn't know it's size
    1054                 :                                          // then none of them do
    1055                 :     {
    1056               0 :        newMaxTotal = PRInt64(-1);
    1057               0 :        break;
    1058                 :     }
    1059                 :     else
    1060               0 :      newMaxTotal += individualProgress;
    1061                 :   }
    1062                 : 
    1063               0 :   PRInt64 progress = -1;
    1064               0 :   if (mMaxSelfProgress >= PRInt64(0) && newMaxTotal >= PRInt64(0))
    1065               0 :     progress = newMaxTotal + mMaxSelfProgress;
    1066                 :   
    1067               0 :   return progress;
    1068                 : }
    1069                 : 
    1070                 : ////////////////////////////////////////////////////////////////////////////////////
    1071                 : // The following section contains support for nsIProgressEventSink which is used to 
    1072                 : // pass progress and status between the actual request and the doc loader. The doc loader
    1073                 : // then turns around and makes the right web progress calls based on this information.
    1074                 : ////////////////////////////////////////////////////////////////////////////////////
    1075                 : 
    1076               0 : NS_IMETHODIMP nsDocLoader::OnProgress(nsIRequest *aRequest, nsISupports* ctxt, 
    1077                 :                                       PRUint64 aProgress, PRUint64 aProgressMax)
    1078                 : {
    1079                 :   nsRequestInfo *info;
    1080               0 :   PRInt64 progressDelta = 0;
    1081                 : 
    1082                 :   //
    1083                 :   // Update the RequestInfo entry with the new progress data
    1084                 :   //
    1085               0 :   info = GetRequestInfo(aRequest);
    1086               0 :   if (info) {
    1087                 :     // suppress sending STATE_TRANSFERRING if this is upload progress (see bug 240053)
    1088               0 :     if (!info->mUploading && (PRInt64(0) == info->mCurrentProgress) && (PRInt64(0) == info->mMaxProgress)) {
    1089                 :       //
    1090                 :       // If we receive an OnProgress event from a toplevel channel that the URI Loader
    1091                 :       // has not yet targeted, then we must suppress the event.  This is necessary to
    1092                 :       // ensure that webprogresslisteners do not get confused when the channel is
    1093                 :       // finally targeted.  See bug 257308.
    1094                 :       //
    1095               0 :       nsLoadFlags lf = 0;
    1096               0 :       aRequest->GetLoadFlags(&lf);
    1097               0 :       if ((lf & nsIChannel::LOAD_DOCUMENT_URI) && !(lf & nsIChannel::LOAD_TARGETED)) {
    1098               0 :         PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
    1099                 :             ("DocLoader:%p Ignoring OnProgress while load is not targeted\n", this));
    1100               0 :         return NS_OK;
    1101                 :       }
    1102                 : 
    1103                 :       //
    1104                 :       // This is the first progress notification for the entry.  If
    1105                 :       // (aMaxProgress > 0) then the content-length of the data is known,
    1106                 :       // so update mMaxSelfProgress...  Otherwise, set it to -1 to indicate
    1107                 :       // that the content-length is no longer known.
    1108                 :       //
    1109               0 :       if (PRUint64(aProgressMax) != LL_MAXUINT) {
    1110               0 :         mMaxSelfProgress  += PRInt64(aProgressMax);
    1111               0 :         info->mMaxProgress = PRInt64(aProgressMax);
    1112                 :       } else {
    1113               0 :         mMaxSelfProgress   =  PRInt64(-1);
    1114               0 :         info->mMaxProgress =  PRInt64(-1);
    1115                 :       }
    1116                 : 
    1117                 :       // Send a STATE_TRANSFERRING notification for the request.
    1118                 :       PRInt32 flags;
    1119                 :     
    1120                 :       flags = nsIWebProgressListener::STATE_TRANSFERRING | 
    1121               0 :               nsIWebProgressListener::STATE_IS_REQUEST;
    1122                 :       //
    1123                 :       // Move the WebProgress into the STATE_TRANSFERRING state if necessary...
    1124                 :       //
    1125               0 :       if (mProgressStateFlags & nsIWebProgressListener::STATE_START) {
    1126               0 :         mProgressStateFlags = nsIWebProgressListener::STATE_TRANSFERRING;
    1127                 : 
    1128                 :         // Send STATE_TRANSFERRING for the document too...
    1129               0 :         flags |= nsIWebProgressListener::STATE_IS_DOCUMENT;
    1130                 :       }
    1131                 : 
    1132               0 :       FireOnStateChange(this, aRequest, flags, NS_OK);
    1133                 :     }
    1134                 : 
    1135                 :     // Update the current progress count...
    1136               0 :     progressDelta = PRInt64(aProgress) - info->mCurrentProgress;
    1137               0 :     mCurrentSelfProgress += progressDelta;
    1138                 : 
    1139               0 :     info->mCurrentProgress = PRInt64(aProgress);
    1140                 :   }
    1141                 :   //
    1142                 :   // The request is not part of the load group, so ignore its progress
    1143                 :   // information...
    1144                 :   //
    1145                 :   else {
    1146                 : #if defined(DEBUG)
    1147               0 :     nsCAutoString buffer;
    1148                 : 
    1149               0 :     GetURIStringFromRequest(aRequest, buffer);
    1150               0 :     PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
    1151                 :            ("DocLoader:%p OOPS - No Request Info for: %s\n",
    1152                 :             this, buffer.get()));
    1153                 : #endif /* DEBUG */
    1154                 : 
    1155               0 :     return NS_OK;
    1156                 :   }
    1157                 : 
    1158                 :   //
    1159                 :   // Fire progress notifications out to any registered nsIWebProgressListeners
    1160                 :   //
    1161                 :   FireOnProgressChange(this, aRequest, aProgress, aProgressMax, progressDelta,
    1162               0 :                        mCurrentTotalProgress, mMaxTotalProgress);
    1163                 : 
    1164               0 :   return NS_OK;
    1165                 : }
    1166                 : 
    1167               0 : NS_IMETHODIMP nsDocLoader::OnStatus(nsIRequest* aRequest, nsISupports* ctxt, 
    1168                 :                                         nsresult aStatus, const PRUnichar* aStatusArg)
    1169                 : {
    1170                 :   //
    1171                 :   // Fire progress notifications out to any registered nsIWebProgressListeners
    1172                 :   //
    1173               0 :   if (aStatus) {
    1174                 :     // Remember the current status for this request
    1175                 :     nsRequestInfo *info;
    1176               0 :     info = GetRequestInfo(aRequest);
    1177               0 :     if (info) {
    1178                 :       bool uploading = (aStatus == nsITransport::STATUS_WRITING ||
    1179               0 :                           aStatus == nsISocketTransport::STATUS_SENDING_TO);
    1180                 :       // If switching from uploading to downloading (or vice versa), then we
    1181                 :       // need to reset our progress counts.  This is designed with HTTP form
    1182                 :       // submission in mind, where an upload is performed followed by download
    1183                 :       // of possibly several documents.
    1184               0 :       if (info->mUploading != uploading) {
    1185               0 :         mCurrentSelfProgress  = mMaxSelfProgress  = LL_ZERO;
    1186               0 :         mCurrentTotalProgress = mMaxTotalProgress = LL_ZERO;
    1187               0 :         mCompletedTotalProgress = LL_ZERO;
    1188               0 :         info->mUploading = uploading;
    1189               0 :         info->mCurrentProgress = LL_ZERO;
    1190               0 :         info->mMaxProgress = LL_ZERO;
    1191                 :       }
    1192                 :     }
    1193                 : 
    1194                 :     nsCOMPtr<nsIStringBundleService> sbs =
    1195               0 :       mozilla::services::GetStringBundleService();
    1196               0 :     if (!sbs)
    1197               0 :       return NS_ERROR_FAILURE;
    1198               0 :     nsXPIDLString msg;
    1199               0 :     nsresult rv = sbs->FormatStatusMessage(aStatus, aStatusArg,
    1200               0 :                                            getter_Copies(msg));
    1201               0 :     if (NS_FAILED(rv))
    1202               0 :       return rv;
    1203                 : 
    1204                 :     // Keep around the message. In case a request finishes, we need to make sure
    1205                 :     // to send the status message of another request to our user to that we
    1206                 :     // don't display, for example, "Transferring" messages for requests that are
    1207                 :     // already done.
    1208               0 :     if (info) {
    1209               0 :       if (!info->mLastStatus) {
    1210               0 :         info->mLastStatus = new nsStatusInfo(aRequest);
    1211                 :       } else {
    1212                 :         // We're going to move it to the front of the list, so remove
    1213                 :         // it from wherever it is now.
    1214               0 :         PR_REMOVE_LINK(info->mLastStatus);
    1215                 :       }
    1216               0 :       info->mLastStatus->mStatusMessage = msg;
    1217               0 :       info->mLastStatus->mStatusCode = aStatus;
    1218                 :       // Put the info at the front of the list
    1219               0 :       PR_INSERT_LINK(info->mLastStatus, &mStatusInfoList);
    1220                 :     }
    1221               0 :     FireOnStatusChange(this, aRequest, aStatus, msg);
    1222                 :   }
    1223               0 :   return NS_OK;
    1224                 : }
    1225                 : 
    1226            1404 : void nsDocLoader::ClearInternalProgress()
    1227                 : {
    1228            1404 :   ClearRequestInfoHash();
    1229                 : 
    1230            1404 :   mCurrentSelfProgress  = mMaxSelfProgress  = LL_ZERO;
    1231            1404 :   mCurrentTotalProgress = mMaxTotalProgress = LL_ZERO;
    1232            1404 :   mCompletedTotalProgress = LL_ZERO;
    1233                 : 
    1234            1404 :   mProgressStateFlags = nsIWebProgressListener::STATE_STOP;
    1235            1404 : }
    1236                 : 
    1237                 : 
    1238               0 : void nsDocLoader::FireOnProgressChange(nsDocLoader *aLoadInitiator,
    1239                 :                                        nsIRequest *request,
    1240                 :                                        PRInt64 aProgress,
    1241                 :                                        PRInt64 aProgressMax,
    1242                 :                                        PRInt64 aProgressDelta,
    1243                 :                                        PRInt64 aTotalProgress,
    1244                 :                                        PRInt64 aMaxTotalProgress)
    1245                 : {
    1246               0 :   if (mIsLoadingDocument) {
    1247               0 :     mCurrentTotalProgress += aProgressDelta;
    1248               0 :     mMaxTotalProgress = GetMaxTotalProgress();
    1249                 : 
    1250               0 :     aTotalProgress    = mCurrentTotalProgress;
    1251               0 :     aMaxTotalProgress = mMaxTotalProgress;
    1252                 :   }
    1253                 : 
    1254                 : #if defined(DEBUG)
    1255               0 :   nsCAutoString buffer;
    1256                 : 
    1257               0 :   GetURIStringFromRequest(request, buffer);
    1258               0 :   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
    1259                 :          ("DocLoader:%p: Progress (%s): curSelf: %d maxSelf: %d curTotal: %d maxTotal %d\n",
    1260                 :           this, buffer.get(), aProgress, aProgressMax, aTotalProgress, aMaxTotalProgress));
    1261                 : #endif /* DEBUG */
    1262                 : 
    1263                 :   /*
    1264                 :    * First notify any listeners of the new progress info...
    1265                 :    *
    1266                 :    * Operate the elements from back to front so that if items get
    1267                 :    * get removed from the list it won't affect our iteration
    1268                 :    */
    1269               0 :   nsCOMPtr<nsIWebProgressListener> listener;
    1270               0 :   PRInt32 count = mListenerInfoList.Count();
    1271                 : 
    1272               0 :   while (--count >= 0) {
    1273                 :     nsListenerInfo *info;
    1274                 : 
    1275               0 :     info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count));
    1276               0 :     if (!info || !(info->mNotifyMask & nsIWebProgress::NOTIFY_PROGRESS)) {
    1277               0 :       continue;
    1278                 :     }
    1279                 : 
    1280               0 :     listener = do_QueryReferent(info->mWeakListener);
    1281               0 :     if (!listener) {
    1282                 :       // the listener went away. gracefully pull it out of the list.
    1283               0 :       mListenerInfoList.RemoveElementAt(count);
    1284               0 :       delete info;
    1285               0 :       continue;
    1286                 :     }
    1287                 : 
    1288                 :     // XXX truncates 64-bit to 32-bit
    1289               0 :     listener->OnProgressChange(aLoadInitiator,request,
    1290                 :                                PRInt32(aProgress), PRInt32(aProgressMax),
    1291               0 :                                PRInt32(aTotalProgress), PRInt32(aMaxTotalProgress));
    1292                 :   }
    1293                 : 
    1294               0 :   mListenerInfoList.Compact();
    1295                 : 
    1296                 :   // Pass the notification up to the parent...
    1297               0 :   if (mParent) {
    1298                 :     mParent->FireOnProgressChange(aLoadInitiator, request,
    1299                 :                                   aProgress, aProgressMax,
    1300                 :                                   aProgressDelta,
    1301               0 :                                   aTotalProgress, aMaxTotalProgress);
    1302                 :   }
    1303               0 : }
    1304                 : 
    1305               0 : void nsDocLoader::GatherAncestorWebProgresses(WebProgressList& aList)
    1306                 : {
    1307               0 :   for (nsDocLoader* loader = this; loader; loader = loader->mParent) {
    1308               0 :     aList.AppendElement(loader);
    1309                 :   }
    1310               0 : }
    1311                 : 
    1312               0 : void nsDocLoader::FireOnStateChange(nsIWebProgress *aProgress,
    1313                 :                                     nsIRequest *aRequest,
    1314                 :                                     PRInt32 aStateFlags,
    1315                 :                                     nsresult aStatus)
    1316                 : {
    1317               0 :   WebProgressList list;
    1318               0 :   GatherAncestorWebProgresses(list);
    1319               0 :   for (PRUint32 i = 0; i < list.Length(); ++i) {
    1320               0 :     list[i]->DoFireOnStateChange(aProgress, aRequest, aStateFlags, aStatus);
    1321                 :   }
    1322               0 : }
    1323                 : 
    1324               0 : void nsDocLoader::DoFireOnStateChange(nsIWebProgress * const aProgress,
    1325                 :                                       nsIRequest * const aRequest,
    1326                 :                                       PRInt32 &aStateFlags,
    1327                 :                                       const nsresult aStatus)
    1328                 : {
    1329                 :   //
    1330                 :   // Remove the STATE_IS_NETWORK bit if necessary.
    1331                 :   //
    1332                 :   // The rule is to remove this bit, if the notification has been passed
    1333                 :   // up from a child WebProgress, and the current WebProgress is already
    1334                 :   // active...
    1335                 :   //
    1336               0 :   if (mIsLoadingDocument &&
    1337                 :       (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) && 
    1338                 :       (this != aProgress)) {
    1339               0 :     aStateFlags &= ~nsIWebProgressListener::STATE_IS_NETWORK;
    1340                 :   }
    1341                 : 
    1342                 :   // Add the STATE_RESTORING bit if necessary.
    1343               0 :   if (mIsRestoringDocument)
    1344               0 :     aStateFlags |= nsIWebProgressListener::STATE_RESTORING;
    1345                 : 
    1346                 : #if defined(DEBUG)
    1347               0 :   nsCAutoString buffer;
    1348                 : 
    1349               0 :   GetURIStringFromRequest(aRequest, buffer);
    1350               0 :   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
    1351                 :          ("DocLoader:%p: Status (%s): code: %x\n",
    1352                 :          this, buffer.get(), aStateFlags));
    1353                 : #endif /* DEBUG */
    1354                 : 
    1355               0 :   NS_ASSERTION(aRequest, "Firing OnStateChange(...) notification with a NULL request!");
    1356                 : 
    1357                 :   /*                                                                           
    1358                 :    * First notify any listeners of the new state info...
    1359                 :    *
    1360                 :    * Operate the elements from back to front so that if items get
    1361                 :    * get removed from the list it won't affect our iteration
    1362                 :    */
    1363               0 :   nsCOMPtr<nsIWebProgressListener> listener;
    1364               0 :   PRInt32 count = mListenerInfoList.Count();
    1365               0 :   PRInt32 notifyMask = (aStateFlags >> 16) & nsIWebProgress::NOTIFY_STATE_ALL;
    1366                 : 
    1367               0 :   while (--count >= 0) {
    1368                 :     nsListenerInfo *info;
    1369                 : 
    1370               0 :     info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count));
    1371               0 :     if (!info || !(info->mNotifyMask & notifyMask)) {
    1372               0 :       continue;
    1373                 :     }
    1374                 : 
    1375               0 :     listener = do_QueryReferent(info->mWeakListener);
    1376               0 :     if (!listener) {
    1377                 :       // the listener went away. gracefully pull it out of the list.
    1378               0 :       mListenerInfoList.RemoveElementAt(count);
    1379               0 :       delete info;
    1380               0 :       continue;
    1381                 :     }
    1382                 : 
    1383               0 :     listener->OnStateChange(aProgress, aRequest, aStateFlags, aStatus);
    1384                 :   }
    1385                 : 
    1386               0 :   mListenerInfoList.Compact();
    1387               0 : }
    1388                 : 
    1389                 : 
    1390                 : 
    1391                 : void
    1392               0 : nsDocLoader::FireOnLocationChange(nsIWebProgress* aWebProgress,
    1393                 :                                   nsIRequest* aRequest,
    1394                 :                                   nsIURI *aUri,
    1395                 :                                   PRUint32 aFlags)
    1396                 : {
    1397                 :   /*                                                                           
    1398                 :    * First notify any listeners of the new state info...
    1399                 :    *
    1400                 :    * Operate the elements from back to front so that if items get
    1401                 :    * get removed from the list it won't affect our iteration
    1402                 :    */
    1403               0 :   nsCOMPtr<nsIWebProgressListener> listener;
    1404               0 :   PRInt32 count = mListenerInfoList.Count();
    1405                 : 
    1406               0 :   while (--count >= 0) {
    1407                 :     nsListenerInfo *info;
    1408                 : 
    1409               0 :     info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count));
    1410               0 :     if (!info || !(info->mNotifyMask & nsIWebProgress::NOTIFY_LOCATION)) {
    1411               0 :       continue;
    1412                 :     }
    1413                 : 
    1414               0 :     listener = do_QueryReferent(info->mWeakListener);
    1415               0 :     if (!listener) {
    1416                 :       // the listener went away. gracefully pull it out of the list.
    1417               0 :       mListenerInfoList.RemoveElementAt(count);
    1418               0 :       delete info;
    1419               0 :       continue;
    1420                 :     }
    1421                 : 
    1422               0 :     listener->OnLocationChange(aWebProgress, aRequest, aUri, aFlags);
    1423                 :   }
    1424                 : 
    1425               0 :   mListenerInfoList.Compact();
    1426                 : 
    1427                 :   // Pass the notification up to the parent...
    1428               0 :   if (mParent) {
    1429               0 :     mParent->FireOnLocationChange(aWebProgress, aRequest, aUri, aFlags);
    1430                 :   }
    1431               0 : }
    1432                 : 
    1433                 : void
    1434               0 : nsDocLoader::FireOnStatusChange(nsIWebProgress* aWebProgress,
    1435                 :                                 nsIRequest* aRequest,
    1436                 :                                 nsresult aStatus,
    1437                 :                                 const PRUnichar* aMessage)
    1438                 : {
    1439                 :   /*                                                                           
    1440                 :    * First notify any listeners of the new state info...
    1441                 :    *
    1442                 :    * Operate the elements from back to front so that if items get
    1443                 :    * get removed from the list it won't affect our iteration
    1444                 :    */
    1445               0 :   nsCOMPtr<nsIWebProgressListener> listener;
    1446               0 :   PRInt32 count = mListenerInfoList.Count();
    1447                 : 
    1448               0 :   while (--count >= 0) {
    1449                 :     nsListenerInfo *info;
    1450                 : 
    1451               0 :     info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count));
    1452               0 :     if (!info || !(info->mNotifyMask & nsIWebProgress::NOTIFY_STATUS)) {
    1453               0 :       continue;
    1454                 :     }
    1455                 : 
    1456               0 :     listener = do_QueryReferent(info->mWeakListener);
    1457               0 :     if (!listener) {
    1458                 :       // the listener went away. gracefully pull it out of the list.
    1459               0 :       mListenerInfoList.RemoveElementAt(count);
    1460               0 :       delete info;
    1461               0 :       continue;
    1462                 :     }
    1463                 : 
    1464               0 :     listener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
    1465                 :   }
    1466               0 :   mListenerInfoList.Compact();
    1467                 :   
    1468                 :   // Pass the notification up to the parent...
    1469               0 :   if (mParent) {
    1470               0 :     mParent->FireOnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
    1471                 :   }
    1472               0 : }
    1473                 : 
    1474                 : bool
    1475               0 : nsDocLoader::RefreshAttempted(nsIWebProgress* aWebProgress,
    1476                 :                               nsIURI *aURI,
    1477                 :                               PRInt32 aDelay,
    1478                 :                               bool aSameURI)
    1479                 : {
    1480                 :   /*
    1481                 :    * Returns true if the refresh may proceed,
    1482                 :    * false if the refresh should be blocked.
    1483                 :    *
    1484                 :    * First notify any listeners of the refresh attempt...
    1485                 :    *
    1486                 :    * Iterate the elements from back to front so that if items
    1487                 :    * get removed from the list it won't affect our iteration
    1488                 :    */
    1489               0 :   bool allowRefresh = true;
    1490               0 :   PRInt32 count = mListenerInfoList.Count();
    1491                 : 
    1492               0 :   while (--count >= 0) {
    1493                 :     nsListenerInfo *info;
    1494                 : 
    1495               0 :     info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count));
    1496               0 :     if (!info || !(info->mNotifyMask & nsIWebProgress::NOTIFY_REFRESH)) {
    1497               0 :       continue;
    1498                 :     }
    1499                 : 
    1500                 :     nsCOMPtr<nsIWebProgressListener> listener =
    1501               0 :       do_QueryReferent(info->mWeakListener);
    1502               0 :     if (!listener) {
    1503                 :       // the listener went away. gracefully pull it out of the list.
    1504               0 :       mListenerInfoList.RemoveElementAt(count);
    1505               0 :       delete info;
    1506               0 :       continue;
    1507                 :     }
    1508                 : 
    1509                 :     nsCOMPtr<nsIWebProgressListener2> listener2 =
    1510               0 :       do_QueryReferent(info->mWeakListener);
    1511               0 :     if (!listener2)
    1512               0 :       continue;
    1513                 : 
    1514                 :     bool listenerAllowedRefresh;
    1515               0 :     nsresult listenerRV = listener2->OnRefreshAttempted(
    1516               0 :         aWebProgress, aURI, aDelay, aSameURI, &listenerAllowedRefresh);
    1517               0 :     if (NS_FAILED(listenerRV))
    1518               0 :       continue;
    1519                 : 
    1520               0 :     allowRefresh = allowRefresh && listenerAllowedRefresh;
    1521                 :   }
    1522                 : 
    1523               0 :   mListenerInfoList.Compact();
    1524                 : 
    1525                 :   // Pass the notification up to the parent...
    1526               0 :   if (mParent) {
    1527                 :     allowRefresh = allowRefresh &&
    1528               0 :       mParent->RefreshAttempted(aWebProgress, aURI, aDelay, aSameURI);
    1529                 :   }
    1530                 : 
    1531               0 :   return allowRefresh;
    1532                 : }
    1533                 : 
    1534                 : nsListenerInfo * 
    1535            1446 : nsDocLoader::GetListenerInfo(nsIWebProgressListener *aListener)
    1536                 : {
    1537                 :   PRInt32 i, count;
    1538                 :   nsListenerInfo *info;
    1539                 : 
    1540            2892 :   nsCOMPtr<nsISupports> listener1 = do_QueryInterface(aListener);
    1541            1446 :   count = mListenerInfoList.Count();
    1542            1488 :   for (i=0; i<count; i++) {
    1543              43 :     info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(i));
    1544                 : 
    1545              43 :     NS_ASSERTION(info, "There should NEVER be a null listener in the list");
    1546              43 :     if (info) {
    1547              86 :       nsCOMPtr<nsISupports> listener2 = do_QueryReferent(info->mWeakListener);
    1548              43 :       if (listener1 == listener2)
    1549               1 :         return info;
    1550                 :     }
    1551                 :   }
    1552            1445 :   return nsnull;
    1553                 : }
    1554                 : 
    1555               0 : nsresult nsDocLoader::AddRequestInfo(nsIRequest *aRequest)
    1556                 : {
    1557               0 :   if (!PL_DHashTableOperate(&mRequestInfoHash, aRequest, PL_DHASH_ADD)) {
    1558               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1559                 :   }
    1560                 : 
    1561               0 :   return NS_OK;
    1562                 : }
    1563                 : 
    1564               0 : void nsDocLoader::RemoveRequestInfo(nsIRequest *aRequest)
    1565                 : {
    1566               0 :   PL_DHashTableOperate(&mRequestInfoHash, aRequest, PL_DHASH_REMOVE);
    1567               0 : }
    1568                 : 
    1569               0 : nsRequestInfo * nsDocLoader::GetRequestInfo(nsIRequest *aRequest)
    1570                 : {
    1571                 :   nsRequestInfo *info =
    1572                 :     static_cast<nsRequestInfo *>
    1573                 :                (PL_DHashTableOperate(&mRequestInfoHash, aRequest,
    1574               0 :                                         PL_DHASH_LOOKUP));
    1575                 : 
    1576               0 :   if (PL_DHASH_ENTRY_IS_FREE(info)) {
    1577                 :     // Nothing found in the hash, return null.
    1578                 : 
    1579               0 :     return nsnull;
    1580                 :   }
    1581                 : 
    1582                 :   // Return what we found in the hash...
    1583                 : 
    1584               0 :   return info;
    1585                 : }
    1586                 : 
    1587                 : // PLDHashTable enumeration callback that just removes every entry
    1588                 : // from the hash.
    1589                 : static PLDHashOperator
    1590               0 : RemoveInfoCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number,
    1591                 :                    void *arg)
    1592                 : {
    1593               0 :   return PL_DHASH_REMOVE;
    1594                 : }
    1595                 : 
    1596            2808 : void nsDocLoader::ClearRequestInfoHash(void)
    1597                 : {
    1598            2808 :   if (!mRequestInfoHash.ops || !mRequestInfoHash.entryCount) {
    1599                 :     // No hash, or the hash is empty, nothing to do here then...
    1600                 : 
    1601            2808 :     return;
    1602                 :   }
    1603                 : 
    1604               0 :   PL_DHashTableEnumerate(&mRequestInfoHash, RemoveInfoCallback, nsnull);
    1605                 : }
    1606                 : 
    1607                 : // PLDHashTable enumeration callback that calculates the max progress.
    1608                 : static PLDHashOperator
    1609               0 : CalcMaxProgressCallback(PLDHashTable *table, PLDHashEntryHdr *hdr,
    1610                 :                         PRUint32 number, void *arg)
    1611                 : {
    1612               0 :   const nsRequestInfo *info = static_cast<const nsRequestInfo *>(hdr);
    1613               0 :   PRInt64 *max = static_cast<PRInt64 *>(arg);
    1614                 : 
    1615               0 :   if (info->mMaxProgress < info->mCurrentProgress) {
    1616               0 :     *max = PRInt64(-1);
    1617                 : 
    1618               0 :     return PL_DHASH_STOP;
    1619                 :   }
    1620                 : 
    1621               0 :   *max += info->mMaxProgress;
    1622                 : 
    1623               0 :   return PL_DHASH_NEXT;
    1624                 : }
    1625                 : 
    1626               0 : PRInt64 nsDocLoader::CalculateMaxProgress()
    1627                 : {
    1628               0 :   PRInt64 max = mCompletedTotalProgress;
    1629               0 :   PL_DHashTableEnumerate(&mRequestInfoHash, CalcMaxProgressCallback, &max);
    1630               0 :   return max;
    1631                 : }
    1632                 : 
    1633               0 : NS_IMETHODIMP nsDocLoader::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
    1634                 :                                                   nsIChannel *aNewChannel,
    1635                 :                                                   PRUint32 aFlags,
    1636                 :                                                   nsIAsyncVerifyRedirectCallback *cb)
    1637                 : {
    1638               0 :   if (aOldChannel)
    1639                 :   {
    1640               0 :     nsLoadFlags loadFlags = 0;
    1641                 :     PRInt32 stateFlags = nsIWebProgressListener::STATE_REDIRECTING |
    1642               0 :                          nsIWebProgressListener::STATE_IS_REQUEST;
    1643                 : 
    1644               0 :     aOldChannel->GetLoadFlags(&loadFlags);
    1645                 :     // If the document channel is being redirected, then indicate that the
    1646                 :     // document is being redirected in the notification...
    1647               0 :     if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
    1648                 :     {
    1649               0 :       stateFlags |= nsIWebProgressListener::STATE_IS_DOCUMENT;
    1650                 : 
    1651                 : #if defined(DEBUG)
    1652               0 :       nsCOMPtr<nsIRequest> request(do_QueryInterface(aOldChannel));
    1653               0 :       NS_ASSERTION(request == mDocumentRequest, "Wrong Document Channel");
    1654                 : #endif /* DEBUG */
    1655                 :     }
    1656                 : 
    1657               0 :     OnRedirectStateChange(aOldChannel, aNewChannel, aFlags, stateFlags);
    1658               0 :     FireOnStateChange(this, aOldChannel, stateFlags, NS_OK);
    1659                 :   }
    1660                 : 
    1661               0 :   cb->OnRedirectVerifyCallback(NS_OK);
    1662               0 :   return NS_OK;
    1663                 : }
    1664                 : 
    1665                 : /*
    1666                 :  * Implementation of nsISecurityEventSink method...
    1667                 :  */
    1668                 : 
    1669               0 : NS_IMETHODIMP nsDocLoader::OnSecurityChange(nsISupports * aContext,
    1670                 :                                             PRUint32 aState)
    1671                 : {
    1672                 :   //
    1673                 :   // Fire progress notifications out to any registered nsIWebProgressListeners.  
    1674                 :   //
    1675                 :   
    1676               0 :   nsCOMPtr<nsIRequest> request = do_QueryInterface(aContext);
    1677               0 :   nsIWebProgress* webProgress = static_cast<nsIWebProgress*>(this);
    1678                 : 
    1679                 :   /*                                                                           
    1680                 :    * First notify any listeners of the new state info...
    1681                 :    *
    1682                 :    * Operate the elements from back to front so that if items get
    1683                 :    * get removed from the list it won't affect our iteration
    1684                 :    */
    1685               0 :   nsCOMPtr<nsIWebProgressListener> listener;
    1686               0 :   PRInt32 count = mListenerInfoList.Count();
    1687                 : 
    1688               0 :   while (--count >= 0) {
    1689                 :     nsListenerInfo *info;
    1690                 : 
    1691               0 :     info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count));
    1692               0 :     if (!info || !(info->mNotifyMask & nsIWebProgress::NOTIFY_SECURITY)) {
    1693               0 :       continue;
    1694                 :     }
    1695                 : 
    1696               0 :     listener = do_QueryReferent(info->mWeakListener);
    1697               0 :     if (!listener) {
    1698                 :       // the listener went away. gracefully pull it out of the list.
    1699               0 :       mListenerInfoList.RemoveElementAt(count);
    1700               0 :       delete info;
    1701               0 :       continue;
    1702                 :     }
    1703                 : 
    1704               0 :     listener->OnSecurityChange(webProgress, request, aState);
    1705                 :   }
    1706                 : 
    1707               0 :   mListenerInfoList.Compact();
    1708                 : 
    1709                 :   // Pass the notification up to the parent...
    1710               0 :   if (mParent) {
    1711               0 :     mParent->OnSecurityChange(aContext, aState);
    1712                 :   }
    1713               0 :   return NS_OK;
    1714                 : }
    1715                 : 
    1716                 : /*
    1717                 :  * Implementation of nsISupportsPriority methods...
    1718                 :  *
    1719                 :  * The priority of the DocLoader _is_ the priority of its LoadGroup.
    1720                 :  *
    1721                 :  * XXX(darin): Once we start storing loadgroups in loadgroups, this code will
    1722                 :  * go away. 
    1723                 :  */
    1724                 : 
    1725               0 : NS_IMETHODIMP nsDocLoader::GetPriority(PRInt32 *aPriority)
    1726                 : {
    1727               0 :   nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup);
    1728               0 :   if (p)
    1729               0 :     return p->GetPriority(aPriority);
    1730                 : 
    1731               0 :   *aPriority = 0;
    1732               0 :   return NS_OK;
    1733                 : }
    1734                 : 
    1735               0 : NS_IMETHODIMP nsDocLoader::SetPriority(PRInt32 aPriority)
    1736                 : {
    1737               0 :   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
    1738                 :          ("DocLoader:%p: SetPriority(%d) called\n", this, aPriority));
    1739                 : 
    1740               0 :   nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup);
    1741               0 :   if (p)
    1742               0 :     p->SetPriority(aPriority);
    1743                 : 
    1744               0 :   PRInt32 count = mChildList.Count();
    1745                 : 
    1746                 :   nsDocLoader *loader;
    1747               0 :   for (PRInt32 i=0; i < count; i++) {
    1748               0 :     loader = static_cast<nsDocLoader*>(ChildAt(i));
    1749               0 :     if (loader) {
    1750               0 :       loader->SetPriority(aPriority);
    1751                 :     }
    1752                 :   }
    1753                 : 
    1754               0 :   return NS_OK;
    1755                 : }
    1756                 : 
    1757               0 : NS_IMETHODIMP nsDocLoader::AdjustPriority(PRInt32 aDelta)
    1758                 : {
    1759               0 :   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
    1760                 :          ("DocLoader:%p: AdjustPriority(%d) called\n", this, aDelta));
    1761                 : 
    1762               0 :   nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup);
    1763               0 :   if (p)
    1764               0 :     p->AdjustPriority(aDelta);
    1765                 : 
    1766               0 :   PRInt32 count = mChildList.Count();
    1767                 : 
    1768                 :   nsDocLoader *loader;
    1769               0 :   for (PRInt32 i=0; i < count; i++) {
    1770               0 :     loader = static_cast<nsDocLoader*>(ChildAt(i));
    1771               0 :     if (loader) {
    1772               0 :       loader->AdjustPriority(aDelta);
    1773                 :     }
    1774                 :   }
    1775                 : 
    1776               0 :   return NS_OK;
    1777                 : }
    1778                 : 
    1779                 : 
    1780                 : 
    1781                 : 
    1782                 : #if 0
    1783                 : void nsDocLoader::DumpChannelInfo()
    1784                 : {
    1785                 :   nsChannelInfo *info;
    1786                 :   PRInt32 i, count;
    1787                 :   PRInt32 current=0, max=0;
    1788                 : 
    1789                 :   
    1790                 :   printf("==== DocLoader=%x\n", this);
    1791                 : 
    1792                 :   count = mChannelInfoList.Count();
    1793                 :   for(i=0; i<count; i++) {
    1794                 :     info = (nsChannelInfo *)mChannelInfoList.ElementAt(i);
    1795                 : 
    1796                 : #if defined(DEBUG)
    1797                 :     nsCAutoString buffer;
    1798                 :     nsresult rv = NS_OK;
    1799                 :     if (info->mURI) {
    1800                 :       rv = info->mURI->GetSpec(buffer);
    1801                 :     }
    1802                 : 
    1803                 :     printf("  [%d] current=%d  max=%d [%s]\n", i,
    1804                 :            info->mCurrentProgress, 
    1805                 :            info->mMaxProgress, buffer.get());
    1806                 : #endif /* DEBUG */
    1807                 : 
    1808                 :     current += info->mCurrentProgress;
    1809                 :     if (max >= 0) {
    1810                 :       if (info->mMaxProgress < info->mCurrentProgress) {
    1811                 :         max = -1;
    1812                 :       } else {
    1813                 :         max += info->mMaxProgress;
    1814                 :       }
    1815                 :     }
    1816                 :   }
    1817                 : 
    1818                 :   printf("\nCurrent=%d   Total=%d\n====\n", current, max);
    1819                 : }
    1820                 : #endif /* 0 */

Generated by: LCOV version 1.7