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
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/
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
15 * The Original Code is Mozilla Communicator client code.
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.
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.
36 * ***** END LICENSE BLOCK ***** */
41 #include "nsDocLoader.h"
42 #include "nsCURILoader.h"
43 #include "nsNetUtil.h"
44 #include "nsIHttpChannel.h"
45 #include "nsIWebProgressListener2.h"
47 #include "nsIServiceManager.h"
48 #include "nsXPIDLString.h"
53 #include "nsWeakPtr.h"
54 #include "nsAutoPtr.h"
56 #include "nsIDOMWindow.h"
58 #include "nsIStringBundle.h"
59 #include "nsIScriptSecurityManager.h"
61 #include "nsITransport.h"
62 #include "nsISocketTransport.h"
64 #include "nsIDOMDocument.h"
65 #include "nsIDocument.h"
66 #include "nsPresContext.h"
67 #include "nsIAsyncVerifyRedirectCallback.h"
69 static NS_DEFINE_CID(kThisImplCID
, NS_THIS_DOCLOADER_IMPL_CID
);
71 #if defined(PR_LOGGING)
73 // Log module for nsIDocumentLoader logging...
75 // To enable logging (see prlog.h for full details):
77 // set NSPR_LOG_MODULES=DocLoader:5
78 // set NSPR_LOG_FILE=nspr.log
80 // this enables PR_LOG_DEBUG level information and places all output in
83 PRLogModuleInfo
* gDocLoaderLog
= nsnull
;
84 #endif /* PR_LOGGING */
88 void GetURIStringFromRequest(nsIRequest
* request
, nsACString
&name
)
91 request
->GetName(name
);
93 name
.AssignLiteral("???");
97 struct nsRequestInfo
: public PLDHashEntryHdr
99 nsRequestInfo(const void *key
)
100 : mKey(key
), mCurrentProgress(0), mMaxProgress(0), mUploading(PR_FALSE
)
105 nsIRequest
* Request() {
106 return static_cast<nsIRequest
*>(const_cast<void*>(mKey
));
109 const void* mKey
; // Must be first for the pldhash stubs to work
110 nsInt64 mCurrentProgress
;
111 nsInt64 mMaxProgress
;
115 nsString mLastStatus
;
116 nsresult mLastStatusCode
;
121 RequestInfoHashInitEntry(PLDHashTable
*table
, PLDHashEntryHdr
*entry
,
124 // Initialize the entry with placement new
125 new (entry
) nsRequestInfo(key
);
130 RequestInfoHashClearEntry(PLDHashTable
*table
, PLDHashEntryHdr
*entry
)
132 nsRequestInfo
* info
= static_cast<nsRequestInfo
*>(entry
);
133 info
->~nsRequestInfo();
136 struct nsListenerInfo
{
137 nsListenerInfo(nsIWeakReference
*aListener
, unsigned long aNotifyMask
)
138 : mWeakListener(aListener
),
139 mNotifyMask(aNotifyMask
)
143 // Weak pointer for the nsIWebProgressListener...
144 nsWeakPtr mWeakListener
;
146 // Mask indicating which notifications the listener wants to receive.
147 unsigned long mNotifyMask
;
151 nsDocLoader::nsDocLoader()
153 mListenerInfoList(8),
154 mIsLoadingDocument(PR_FALSE
),
155 mIsRestoringDocument(PR_FALSE
),
156 mDontFlushLayout(PR_FALSE
),
157 mIsFlushingLayout(PR_FALSE
)
159 #if defined(PR_LOGGING)
160 if (nsnull
== gDocLoaderLog
) {
161 gDocLoaderLog
= PR_NewLogModule("DocLoader");
163 #endif /* PR_LOGGING */
165 static PLDHashTableOps hash_table_ops
=
169 PL_DHashVoidPtrKeyStub
,
170 PL_DHashMatchEntryStub
,
171 PL_DHashMoveEntryStub
,
172 RequestInfoHashClearEntry
,
173 PL_DHashFinalizeStub
,
174 RequestInfoHashInitEntry
177 if (!PL_DHashTableInit(&mRequestInfoHash
, &hash_table_ops
, nsnull
,
178 sizeof(nsRequestInfo
), 16)) {
179 mRequestInfoHash
.ops
= nsnull
;
182 ClearInternalProgress();
184 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
185 ("DocLoader:%p: created.\n", this));
189 nsDocLoader::SetDocLoaderParent(nsDocLoader
*aParent
)
198 if (!mRequestInfoHash
.ops
) {
199 return NS_ERROR_OUT_OF_MEMORY
;
202 nsresult rv
= NS_NewLoadGroup(getter_AddRefs(mLoadGroup
), this);
203 if (NS_FAILED(rv
)) return rv
;
205 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
206 ("DocLoader:%p: load group %x.\n", this, mLoadGroup
.get()));
211 nsDocLoader::~nsDocLoader()
214 |ClearWeakReferences()| here is intended to prevent people holding weak references
215 from re-entering this destructor since |QueryReferent()| will |AddRef()| me, and the
216 subsequent |Release()| will try to destroy me. At this point there should be only
217 weak references remaining (otherwise, we wouldn't be getting destroyed).
219 An alternative would be incrementing our refcount (consider it a compressed flag
220 saying "Don't re-destroy."). I haven't yet decided which is better. [scc]
222 // XXXbz now that NS_IMPL_RELEASE stabilizes by setting refcount to 1, is
224 ClearWeakReferences();
228 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
229 ("DocLoader:%p: deleted.\n", this));
231 if (mRequestInfoHash
.ops
) {
232 PL_DHashTableFinish(&mRequestInfoHash
);
238 * Implementation of ISupports methods...
240 NS_IMPL_THREADSAFE_ADDREF(nsDocLoader
)
241 NS_IMPL_THREADSAFE_RELEASE(nsDocLoader
)
243 NS_INTERFACE_MAP_BEGIN(nsDocLoader
)
244 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIRequestObserver
)
245 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver
)
246 NS_INTERFACE_MAP_ENTRY(nsIDocumentLoader
)
247 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
248 NS_INTERFACE_MAP_ENTRY(nsIWebProgress
)
249 NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink
)
250 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
251 NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink
)
252 NS_INTERFACE_MAP_ENTRY(nsISecurityEventSink
)
253 NS_INTERFACE_MAP_ENTRY(nsISupportsPriority
)
254 if (aIID
.Equals(kThisImplCID
))
255 foundInterface
= static_cast<nsIDocumentLoader
*>(this);
261 * Implementation of nsIInterfaceRequestor methods...
263 NS_IMETHODIMP
nsDocLoader::GetInterface(const nsIID
& aIID
, void** aSink
)
265 nsresult rv
= NS_ERROR_NO_INTERFACE
;
267 NS_ENSURE_ARG_POINTER(aSink
);
269 if(aIID
.Equals(NS_GET_IID(nsILoadGroup
))) {
271 NS_IF_ADDREF((nsISupports
*)*aSink
);
274 rv
= QueryInterface(aIID
, aSink
);
281 already_AddRefed
<nsDocLoader
>
282 nsDocLoader::GetAsDocLoader(nsISupports
* aSupports
)
289 CallQueryInterface(aSupports
, &ptr
);
295 nsDocLoader::AddDocLoaderAsChildOfRoot(nsDocLoader
* aDocLoader
)
298 nsCOMPtr
<nsIDocumentLoader
> docLoaderService
=
299 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID
, &rv
);
300 NS_ENSURE_SUCCESS(rv
, rv
);
302 nsRefPtr
<nsDocLoader
> rootDocLoader
= GetAsDocLoader(docLoaderService
);
303 NS_ENSURE_TRUE(rootDocLoader
, NS_ERROR_UNEXPECTED
);
305 return rootDocLoader
->AddChildLoader(aDocLoader
);
309 nsDocLoader::Stop(void)
314 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
315 ("DocLoader:%p: Stop() called\n", this));
317 count
= mChildList
.Count();
319 nsCOMPtr
<nsIDocumentLoader
> loader
;
320 for (i
=0; i
< count
; i
++) {
324 (void) loader
->Stop();
329 rv
= mLoadGroup
->Cancel(NS_BINDING_ABORTED
);
331 // Don't report that we're flushing layout so IsBusy returns false after a
333 mIsFlushingLayout
= PR_FALSE
;
335 // Clear out mChildrenInOnload. We want to make sure to fire our
336 // onload at this point, and there's no issue with mChildrenInOnload
337 // after this, since mDocumentRequest will be null after the
338 // DocLoaderIsEmpty() call.
339 mChildrenInOnload
.Clear();
341 // Make sure to call DocLoaderIsEmpty now so that we reset mDocumentRequest,
342 // etc, as needed. We could be getting into here from a subframe onload, in
343 // which case the call to DocLoaderIsEmpty() is coming but hasn't quite
344 // happened yet, Canceling the loadgroup did nothing (because it was already
345 // empty), and we're about to start a new load (which is what triggered this
348 // XXXbz If the child frame loadgroups were requests in mLoadgroup, I suspect
349 // we wouldn't need the call here....
351 NS_ASSERTION(!IsBusy(), "Shouldn't be busy here");
352 DocLoaderIsEmpty(PR_FALSE
);
359 nsDocLoader::IsBusy()
364 // A document loader is busy if either:
366 // 1. One of its children is in the middle of an onload handler. Note that
367 // the handler may have already removed this child from mChildList!
368 // 2. It is currently loading a document and either has parts of it still
369 // loading, or has a busy child docloader.
370 // 3. It's currently flushing layout in DocLoaderIsEmpty().
373 if (mChildrenInOnload
.Count() || mIsFlushingLayout
) {
377 /* Is this document loader busy? */
378 if (!mIsLoadingDocument
) {
383 rv
= mLoadGroup
->IsPending(&busy
);
391 /* check its child document loaders... */
394 count
= mChildList
.Count();
396 for (i
=0; i
< count
; i
++) {
397 nsIDocumentLoader
* loader
= ChildAt(i
);
399 // This is a safe cast, because we only put nsDocLoader objects into the
401 if (loader
&& static_cast<nsDocLoader
*>(loader
)->IsBusy())
409 nsDocLoader::GetContainer(nsISupports
** aResult
)
411 NS_ADDREF(*aResult
= static_cast<nsIDocumentLoader
*>(this));
417 nsDocLoader::GetLoadGroup(nsILoadGroup
** aResult
)
421 if (nsnull
== aResult
) {
422 rv
= NS_ERROR_NULL_POINTER
;
424 *aResult
= mLoadGroup
;
425 NS_IF_ADDREF(*aResult
);
431 nsDocLoader::Destroy()
435 // Remove the document loader from the parent list of loaders...
438 mParent
->RemoveChildLoader(this);
441 // Release all the information about network requests...
442 ClearRequestInfoHash();
444 // Release all the information about registered listeners...
445 PRInt32 count
= mListenerInfoList
.Count();
446 for(PRInt32 i
= 0; i
< count
; i
++) {
447 nsListenerInfo
*info
=
448 static_cast<nsListenerInfo
*>(mListenerInfoList
.ElementAt(i
));
453 mListenerInfoList
.Clear();
454 mListenerInfoList
.Compact();
456 mDocumentRequest
= 0;
459 mLoadGroup
->SetGroupObserver(nsnull
);
465 nsDocLoader::DestroyChildren()
469 count
= mChildList
.Count();
470 // if the doc loader still has children...we need to enumerate the
471 // children and make them null out their back ptr to the parent doc
473 for (i
=0; i
< count
; i
++)
475 nsIDocumentLoader
* loader
= ChildAt(i
);
478 // This is a safe cast, as we only put nsDocLoader objects into the
480 static_cast<nsDocLoader
*>(loader
)->SetDocLoaderParent(nsnull
);
487 nsDocLoader::OnStartRequest(nsIRequest
*request
, nsISupports
*aCtxt
)
489 // called each time a request is added to the group.
492 if (PR_LOG_TEST(gDocLoaderLog
, PR_LOG_DEBUG
)) {
494 request
->GetName(name
);
498 mLoadGroup
->GetActiveCount(&count
);
500 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
501 ("DocLoader:%p: OnStartRequest[%p](%s) mIsLoadingDocument=%s, %u active URLs",
502 this, request
, name
.get(),
503 (mIsLoadingDocument
? "true" : "false"),
506 #endif /* PR_LOGGING */
507 PRBool bJustStartedLoading
= PR_FALSE
;
509 nsLoadFlags loadFlags
= 0;
510 request
->GetLoadFlags(&loadFlags
);
512 if (!mIsLoadingDocument
&& (loadFlags
& nsIChannel::LOAD_DOCUMENT_URI
)) {
513 bJustStartedLoading
= PR_TRUE
;
514 mIsLoadingDocument
= PR_TRUE
;
515 ClearInternalProgress(); // only clear our progress if we are starting a new load....
519 // Create a new nsRequestInfo for the request that is starting to
522 AddRequestInfo(request
);
525 // Only fire a doStartDocumentLoad(...) if the document loader
526 // has initiated a load... Otherwise, this notification has
527 // resulted from a request being added to the load group.
529 if (mIsLoadingDocument
) {
530 if (loadFlags
& nsIChannel::LOAD_DOCUMENT_URI
) {
532 // Make sure that the document channel is null at this point...
533 // (unless its been redirected)
535 NS_ASSERTION((loadFlags
& nsIChannel::LOAD_REPLACE
) ||
536 !(mDocumentRequest
.get()),
537 "Overwriting an existing document channel!");
539 // This request is associated with the entire document...
540 mDocumentRequest
= request
;
541 mLoadGroup
->SetDefaultLoadRequest(request
);
543 // Only fire the start document load notification for the first
544 // document URI... Do not fire it again for redirections
546 if (bJustStartedLoading
) {
547 // Update the progress status state
548 mProgressStateFlags
= nsIWebProgressListener::STATE_START
;
550 // Fire the start document load notification
551 doStartDocumentLoad();
557 NS_ASSERTION(!mIsLoadingDocument
|| mDocumentRequest
,
558 "mDocumentRequest MUST be set for the duration of a page load!");
560 doStartURLLoad(request
);
566 nsDocLoader::OnStopRequest(nsIRequest
*aRequest
,
573 if (PR_LOG_TEST(gDocLoaderLog
, PR_LOG_DEBUG
)) {
575 aRequest
->GetName(name
);
579 mLoadGroup
->GetActiveCount(&count
);
581 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
582 ("DocLoader:%p: OnStopRequest[%p](%s) status=%x mIsLoadingDocument=%s, %u active URLs",
583 this, aRequest
, name
.get(),
584 aStatus
, (mIsLoadingDocument
? "true" : "false"),
589 PRBool bFireTransferring
= PR_FALSE
;
592 // Set the Maximum progress to the same value as the current progress.
593 // Since the URI has finished loading, all the data is there. Also,
594 // this will allow a more accurate estimation of the max progress (in case
595 // the old value was unknown ie. -1)
597 nsRequestInfo
*info
= GetRequestInfo(aRequest
);
599 info
->mIsDone
= PR_TRUE
;
601 nsInt64 oldMax
= info
->mMaxProgress
;
603 info
->mMaxProgress
= info
->mCurrentProgress
;
606 // If a request whose content-length was previously unknown has just
607 // finished loading, then use this new data to try to calculate a
608 // mMaxSelfProgress...
610 if ((oldMax
< nsInt64(0)) && (mMaxSelfProgress
< nsInt64(0))) {
611 mMaxSelfProgress
= CalculateMaxProgress();
614 // As we know the total progress of this request now, save it to be part
615 // of CalculateMaxProgress() result. We need to remove the info from the
616 // hash, see bug 480713.
617 mCompletedTotalProgress
+= info
->mMaxProgress
;
620 // Determine whether a STATE_TRANSFERRING notification should be
623 // If nsRequestInfo::mMaxProgress (as stored in oldMax) and
624 // nsRequestInfo::mCurrentProgress are both 0, then the
625 // STATE_TRANSFERRING notification has not been fired yet...
627 if ((oldMax
== LL_ZERO
) && (info
->mCurrentProgress
== LL_ZERO
)) {
628 nsCOMPtr
<nsIChannel
> channel(do_QueryInterface(aRequest
));
630 // Only fire a TRANSFERRING notification if the request is also a
631 // channel -- data transfer requires a nsIChannel!
634 if (NS_SUCCEEDED(aStatus
)) {
635 bFireTransferring
= PR_TRUE
;
638 // If the request failed (for any reason other than being
639 // redirected or retargeted), the TRANSFERRING notification can
640 // still be fired if a HTTP connection was established to a server.
642 else if (aStatus
!= NS_BINDING_REDIRECTED
&&
643 aStatus
!= NS_BINDING_RETARGETED
) {
645 // Only if the load has been targeted (see bug 268483)...
648 channel
->GetLoadFlags(&lf
);
649 if (lf
& nsIChannel::LOAD_TARGETED
) {
650 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aRequest
));
652 PRUint32 responseCode
;
653 rv
= httpChannel
->GetResponseStatus(&responseCode
);
654 if (NS_SUCCEEDED(rv
)) {
656 // A valid server status indicates that a connection was
657 // established to the server... So, fire the notification
658 // even though a failure occurred later...
660 bFireTransferring
= PR_TRUE
;
669 if (bFireTransferring
) {
670 // Send a STATE_TRANSFERRING notification for the request.
673 flags
= nsIWebProgressListener::STATE_TRANSFERRING
|
674 nsIWebProgressListener::STATE_IS_REQUEST
;
676 // Move the WebProgress into the STATE_TRANSFERRING state if necessary...
678 if (mProgressStateFlags
& nsIWebProgressListener::STATE_START
) {
679 mProgressStateFlags
= nsIWebProgressListener::STATE_TRANSFERRING
;
681 // Send STATE_TRANSFERRING for the document too...
682 flags
|= nsIWebProgressListener::STATE_IS_DOCUMENT
;
685 FireOnStateChange(this, aRequest
, flags
, NS_OK
);
689 // Fire the OnStateChange(...) notification for stop request
691 doStopURLLoad(aRequest
, aStatus
);
693 // Clear this request out of the hash to avoid bypass of FireOnStateChange
694 // when address of the request is reused.
695 RemoveRequestInfo(aRequest
);
698 // Only fire the DocLoaderIsEmpty(...) if the document loader has initiated a
699 // load. This will handle removing the request from our hashtable as needed.
701 if (mIsLoadingDocument
) {
702 DocLoaderIsEmpty(PR_TRUE
);
709 nsresult
nsDocLoader::RemoveChildLoader(nsDocLoader
* aChild
)
711 nsresult rv
= mChildList
.RemoveElement(aChild
) ? NS_OK
: NS_ERROR_FAILURE
;
712 if (NS_SUCCEEDED(rv
)) {
713 aChild
->SetDocLoaderParent(nsnull
);
718 nsresult
nsDocLoader::AddChildLoader(nsDocLoader
* aChild
)
720 nsresult rv
= mChildList
.AppendElement(aChild
) ? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
721 if (NS_SUCCEEDED(rv
)) {
722 aChild
->SetDocLoaderParent(this);
727 NS_IMETHODIMP
nsDocLoader::GetDocumentChannel(nsIChannel
** aChannel
)
729 if (!mDocumentRequest
) {
734 return CallQueryInterface(mDocumentRequest
, aChannel
);
738 void nsDocLoader::DocLoaderIsEmpty(PRBool aFlushLayout
)
740 if (mIsLoadingDocument
) {
741 /* In the unimagineably rude circumstance that onload event handlers
742 triggered by this function actually kill the window ... ok, it's
743 not unimagineable; it's happened ... this deathgrip keeps this object
744 alive long enough to survive this function call. */
745 nsCOMPtr
<nsIDocumentLoader
> kungFuDeathGrip(this);
747 // Don't flush layout if we're still busy.
752 NS_ASSERTION(!mIsFlushingLayout
, "Someone screwed up");
754 // The load group for this DocumentLoader is idle. Flush if we need to.
755 if (aFlushLayout
&& !mDontFlushLayout
) {
756 nsCOMPtr
<nsIDOMDocument
> domDoc
= do_GetInterface(GetAsSupports(this));
757 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
759 // We start loads from style resolution, so we need to flush out style
760 // no matter what. If we have user fonts, we also need to flush layout,
761 // since the reflow is what starts font loads.
762 mozFlushType flushType
= Flush_Style
;
763 nsIPresShell
* shell
= doc
->GetShell();
765 // Be safe in case this presshell is in teardown now
766 nsPresContext
* presContext
= shell
->GetPresContext();
767 if (presContext
&& presContext
->GetUserFontSet()) {
768 flushType
= Flush_Layout
;
771 mDontFlushLayout
= mIsFlushingLayout
= PR_TRUE
;
772 doc
->FlushPendingNotifications(flushType
);
773 mDontFlushLayout
= mIsFlushingLayout
= PR_FALSE
;
777 // And now check whether we're really busy; that might have changed with
780 // Clear out our request info hash, now that our load really is done and
781 // we don't need it anymore to CalculateMaxProgress().
782 ClearInternalProgress();
784 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
785 ("DocLoader:%p: Is now idle...\n", this));
787 nsCOMPtr
<nsIRequest
> docRequest
= mDocumentRequest
;
789 NS_ASSERTION(mDocumentRequest
, "No Document Request!");
790 mDocumentRequest
= 0;
791 mIsLoadingDocument
= PR_FALSE
;
793 // Update the progress status state - the document is done
794 mProgressStateFlags
= nsIWebProgressListener::STATE_STOP
;
797 nsresult loadGroupStatus
= NS_OK
;
798 mLoadGroup
->GetStatus(&loadGroupStatus
);
801 // New code to break the circular reference between
802 // the load group and the docloader...
804 mLoadGroup
->SetDefaultLoadRequest(nsnull
);
806 // Take a ref to our parent now so that we can call DocLoaderIsEmpty() on
807 // it even if our onload handler removes us from the docloader tree.
808 nsRefPtr
<nsDocLoader
> parent
= mParent
;
810 // Note that if calling ChildEnteringOnload() on the parent returns false
811 // then calling our onload handler is not safe. That can only happen on
812 // OOM, so that's ok.
813 if (!parent
|| parent
->ChildEnteringOnload(this)) {
814 // Do nothing with our state after firing the
815 // OnEndDocumentLoad(...). The document loader may be loading a *new*
816 // document - if LoadDocument() was called from a handler!
818 doStopDocumentLoad(docRequest
, loadGroupStatus
);
821 parent
->ChildDoneWithOnload(this);
828 void nsDocLoader::doStartDocumentLoad(void)
832 nsCAutoString buffer
;
834 GetURIStringFromRequest(mDocumentRequest
, buffer
);
835 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
836 ("DocLoader:%p: ++ Firing OnStateChange for start document load (...)."
838 this, buffer
.get()));
841 // Fire an OnStatus(...) notification STATE_START. This indicates
842 // that the document represented by mDocumentRequest has started to
844 FireOnStateChange(this,
846 nsIWebProgressListener::STATE_START
|
847 nsIWebProgressListener::STATE_IS_DOCUMENT
|
848 nsIWebProgressListener::STATE_IS_REQUEST
|
849 nsIWebProgressListener::STATE_IS_WINDOW
|
850 nsIWebProgressListener::STATE_IS_NETWORK
,
854 void nsDocLoader::doStartURLLoad(nsIRequest
*request
)
857 nsCAutoString buffer
;
859 GetURIStringFromRequest(request
, buffer
);
860 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
861 ("DocLoader:%p: ++ Firing OnStateChange start url load (...)."
863 this, buffer
.get()));
866 FireOnStateChange(this,
868 nsIWebProgressListener::STATE_START
|
869 nsIWebProgressListener::STATE_IS_REQUEST
,
873 // PLDHashTable enumeration callback that finds a RequestInfo that's not done
875 static PLDHashOperator
876 FindUnfinishedRequestCallback(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
877 PRUint32 number
, void *arg
)
879 nsRequestInfo
* info
= static_cast<nsRequestInfo
*>(hdr
);
880 nsRequestInfo
** retval
= static_cast<nsRequestInfo
**>(arg
);
882 if (!info
->mIsDone
&& !info
->mLastStatus
.IsEmpty()) {
884 return PL_DHASH_STOP
;
887 return PL_DHASH_NEXT
;
891 void nsDocLoader::doStopURLLoad(nsIRequest
*request
, nsresult aStatus
)
894 nsCAutoString buffer
;
896 GetURIStringFromRequest(request
, buffer
);
897 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
898 ("DocLoader:%p: ++ Firing OnStateChange for end url load (...)."
899 "\tURI: %s status=%x\n",
900 this, buffer
.get(), aStatus
));
903 FireOnStateChange(this,
905 nsIWebProgressListener::STATE_STOP
|
906 nsIWebProgressListener::STATE_IS_REQUEST
,
909 // Fire a status change message for a random unfinished request to make sure
910 // that the displayed status is not outdated.
911 nsRequestInfo
* unfinishedRequest
= nsnull
;
912 PL_DHashTableEnumerate(&mRequestInfoHash
, FindUnfinishedRequestCallback
,
914 if (unfinishedRequest
) {
915 FireOnStatusChange(this, unfinishedRequest
->Request(),
916 unfinishedRequest
->mLastStatusCode
,
917 unfinishedRequest
->mLastStatus
.get());
921 void nsDocLoader::doStopDocumentLoad(nsIRequest
*request
,
925 nsCAutoString buffer
;
927 GetURIStringFromRequest(request
, buffer
);
928 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
929 ("DocLoader:%p: ++ Firing OnStateChange for end document load (...)."
930 "\tURI: %s Status=%x\n",
931 this, buffer
.get(), aStatus
));
935 // Fire an OnStateChange(...) notification indicating the the
936 // current document has finished loading...
938 FireOnStateChange(this,
940 nsIWebProgressListener::STATE_STOP
|
941 nsIWebProgressListener::STATE_IS_DOCUMENT
,
945 // Fire a final OnStateChange(...) notification indicating the the
946 // current document has finished loading...
948 FireOnStateChange(this,
950 nsIWebProgressListener::STATE_STOP
|
951 nsIWebProgressListener::STATE_IS_WINDOW
|
952 nsIWebProgressListener::STATE_IS_NETWORK
,
956 ////////////////////////////////////////////////////////////////////////////////////
957 // The following section contains support for nsIWebProgress and related stuff
958 ////////////////////////////////////////////////////////////////////////////////////
961 nsDocLoader::AddProgressListener(nsIWebProgressListener
*aListener
,
962 PRUint32 aNotifyMask
)
966 nsListenerInfo
* info
= GetListenerInfo(aListener
);
968 // The listener is already registered!
969 return NS_ERROR_FAILURE
;
972 nsWeakPtr listener
= do_GetWeakReference(aListener
);
974 return NS_ERROR_INVALID_ARG
;
977 info
= new nsListenerInfo(listener
, aNotifyMask
);
979 return NS_ERROR_OUT_OF_MEMORY
;
982 rv
= mListenerInfoList
.AppendElement(info
) ? NS_OK
: NS_ERROR_FAILURE
;
987 nsDocLoader::RemoveProgressListener(nsIWebProgressListener
*aListener
)
991 nsListenerInfo
* info
= GetListenerInfo(aListener
);
993 rv
= mListenerInfoList
.RemoveElement(info
) ? NS_OK
: NS_ERROR_FAILURE
;
996 // The listener is not registered!
997 rv
= NS_ERROR_FAILURE
;
1003 nsDocLoader::GetDOMWindow(nsIDOMWindow
**aResult
)
1005 return CallGetInterface(this, aResult
);
1009 nsDocLoader::GetIsLoadingDocument(PRBool
*aIsLoadingDocument
)
1011 *aIsLoadingDocument
= mIsLoadingDocument
;
1016 PRInt64
nsDocLoader::GetMaxTotalProgress()
1018 nsInt64 newMaxTotal
= 0;
1020 PRInt32 count
= mChildList
.Count();
1021 nsCOMPtr
<nsIWebProgress
> webProgress
;
1022 for (PRInt32 i
=0; i
< count
; i
++)
1024 nsInt64 individualProgress
= 0;
1025 nsIDocumentLoader
* docloader
= ChildAt(i
);
1028 // Cast is safe since all children are nsDocLoader too
1029 individualProgress
= ((nsDocLoader
*) docloader
)->GetMaxTotalProgress();
1031 if (individualProgress
< nsInt64(0)) // if one of the elements doesn't know it's size
1032 // then none of them do
1034 newMaxTotal
= nsInt64(-1);
1038 newMaxTotal
+= individualProgress
;
1041 nsInt64 progress
= -1;
1042 if (mMaxSelfProgress
>= nsInt64(0) && newMaxTotal
>= nsInt64(0))
1043 progress
= newMaxTotal
+ mMaxSelfProgress
;
1048 ////////////////////////////////////////////////////////////////////////////////////
1049 // The following section contains support for nsIProgressEventSink which is used to
1050 // pass progress and status between the actual request and the doc loader. The doc loader
1051 // then turns around and makes the right web progress calls based on this information.
1052 ////////////////////////////////////////////////////////////////////////////////////
1054 NS_IMETHODIMP
nsDocLoader::OnProgress(nsIRequest
*aRequest
, nsISupports
* ctxt
,
1055 PRUint64 aProgress
, PRUint64 aProgressMax
)
1057 nsRequestInfo
*info
;
1058 nsInt64 progressDelta
= 0;
1061 // Update the RequestInfo entry with the new progress data
1063 info
= GetRequestInfo(aRequest
);
1065 // suppress sending STATE_TRANSFERRING if this is upload progress (see bug 240053)
1066 if (!info
->mUploading
&& (nsInt64(0) == info
->mCurrentProgress
) && (nsInt64(0) == info
->mMaxProgress
)) {
1068 // If we receive an OnProgress event from a toplevel channel that the URI Loader
1069 // has not yet targeted, then we must suppress the event. This is necessary to
1070 // ensure that webprogresslisteners do not get confused when the channel is
1071 // finally targeted. See bug 257308.
1074 aRequest
->GetLoadFlags(&lf
);
1075 if ((lf
& nsIChannel::LOAD_DOCUMENT_URI
) && !(lf
& nsIChannel::LOAD_TARGETED
)) {
1076 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1077 ("DocLoader:%p Ignoring OnProgress while load is not targeted\n", this));
1082 // This is the first progress notification for the entry. If
1083 // (aMaxProgress > 0) then the content-length of the data is known,
1084 // so update mMaxSelfProgress... Otherwise, set it to -1 to indicate
1085 // that the content-length is no longer known.
1087 if (PRUint64(aProgressMax
) != LL_MAXUINT
) {
1088 mMaxSelfProgress
+= PRInt64(aProgressMax
);
1089 info
->mMaxProgress
= PRInt64(aProgressMax
);
1091 mMaxSelfProgress
= nsInt64(-1);
1092 info
->mMaxProgress
= nsInt64(-1);
1095 // Send a STATE_TRANSFERRING notification for the request.
1098 flags
= nsIWebProgressListener::STATE_TRANSFERRING
|
1099 nsIWebProgressListener::STATE_IS_REQUEST
;
1101 // Move the WebProgress into the STATE_TRANSFERRING state if necessary...
1103 if (mProgressStateFlags
& nsIWebProgressListener::STATE_START
) {
1104 mProgressStateFlags
= nsIWebProgressListener::STATE_TRANSFERRING
;
1106 // Send STATE_TRANSFERRING for the document too...
1107 flags
|= nsIWebProgressListener::STATE_IS_DOCUMENT
;
1110 FireOnStateChange(this, aRequest
, flags
, NS_OK
);
1113 // Update the current progress count...
1114 progressDelta
= nsInt64(PRInt64(aProgress
)) - info
->mCurrentProgress
;
1115 mCurrentSelfProgress
+= progressDelta
;
1117 info
->mCurrentProgress
= PRInt64(aProgress
);
1120 // The request is not part of the load group, so ignore its progress
1125 nsCAutoString buffer
;
1127 GetURIStringFromRequest(aRequest
, buffer
);
1128 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1129 ("DocLoader:%p OOPS - No Request Info for: %s\n",
1130 this, buffer
.get()));
1137 // Fire progress notifications out to any registered nsIWebProgressListeners
1139 FireOnProgressChange(this, aRequest
, aProgress
, aProgressMax
, progressDelta
,
1140 mCurrentTotalProgress
, mMaxTotalProgress
);
1145 NS_IMETHODIMP
nsDocLoader::OnStatus(nsIRequest
* aRequest
, nsISupports
* ctxt
,
1146 nsresult aStatus
, const PRUnichar
* aStatusArg
)
1149 // Fire progress notifications out to any registered nsIWebProgressListeners
1152 // Remember the current status for this request
1153 nsRequestInfo
*info
;
1154 info
= GetRequestInfo(aRequest
);
1156 PRBool uploading
= (aStatus
== nsITransport::STATUS_WRITING
||
1157 aStatus
== nsISocketTransport::STATUS_SENDING_TO
);
1158 // If switching from uploading to downloading (or vice versa), then we
1159 // need to reset our progress counts. This is designed with HTTP form
1160 // submission in mind, where an upload is performed followed by download
1161 // of possibly several documents.
1162 if (info
->mUploading
!= uploading
) {
1163 mCurrentSelfProgress
= mMaxSelfProgress
= LL_ZERO
;
1164 mCurrentTotalProgress
= mMaxTotalProgress
= LL_ZERO
;
1165 mCompletedTotalProgress
= LL_ZERO
;
1166 info
->mUploading
= uploading
;
1167 info
->mCurrentProgress
= LL_ZERO
;
1168 info
->mMaxProgress
= LL_ZERO
;
1172 nsCOMPtr
<nsIStringBundleService
> sbs
=
1173 mozilla::services::GetStringBundleService();
1175 return NS_ERROR_FAILURE
;
1177 nsresult rv
= sbs
->FormatStatusMessage(aStatus
, aStatusArg
,
1178 getter_Copies(msg
));
1182 // Keep around the message. In case a request finishes, we need to make sure
1183 // to send the status message of another request to our user to that we
1184 // don't display, for example, "Transferring" messages for requests that are
1187 info
->mLastStatus
= msg
;
1188 info
->mLastStatusCode
= aStatus
;
1190 FireOnStatusChange(this, aRequest
, aStatus
, msg
);
1195 void nsDocLoader::ClearInternalProgress()
1197 ClearRequestInfoHash();
1199 mCurrentSelfProgress
= mMaxSelfProgress
= LL_ZERO
;
1200 mCurrentTotalProgress
= mMaxTotalProgress
= LL_ZERO
;
1201 mCompletedTotalProgress
= LL_ZERO
;
1203 mProgressStateFlags
= nsIWebProgressListener::STATE_STOP
;
1207 void nsDocLoader::FireOnProgressChange(nsDocLoader
*aLoadInitiator
,
1208 nsIRequest
*request
,
1210 PRInt64 aProgressMax
,
1211 PRInt64 aProgressDelta
,
1212 PRInt64 aTotalProgress
,
1213 PRInt64 aMaxTotalProgress
)
1215 if (mIsLoadingDocument
) {
1216 mCurrentTotalProgress
+= aProgressDelta
;
1217 mMaxTotalProgress
= GetMaxTotalProgress();
1219 aTotalProgress
= mCurrentTotalProgress
;
1220 aMaxTotalProgress
= mMaxTotalProgress
;
1224 nsCAutoString buffer
;
1226 GetURIStringFromRequest(request
, buffer
);
1227 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1228 ("DocLoader:%p: Progress (%s): curSelf: %d maxSelf: %d curTotal: %d maxTotal %d\n",
1229 this, buffer
.get(), aProgress
, aProgressMax
, aTotalProgress
, aMaxTotalProgress
));
1233 * First notify any listeners of the new progress info...
1235 * Operate the elements from back to front so that if items get
1236 * get removed from the list it won't affect our iteration
1238 nsCOMPtr
<nsIWebProgressListener
> listener
;
1239 PRInt32 count
= mListenerInfoList
.Count();
1241 while (--count
>= 0) {
1242 nsListenerInfo
*info
;
1244 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1245 if (!info
|| !(info
->mNotifyMask
& nsIWebProgress::NOTIFY_PROGRESS
)) {
1249 listener
= do_QueryReferent(info
->mWeakListener
);
1251 // the listener went away. gracefully pull it out of the list.
1252 mListenerInfoList
.RemoveElementAt(count
);
1257 // XXX truncates 64-bit to 32-bit
1258 listener
->OnProgressChange(aLoadInitiator
,request
,
1259 PRInt32(aProgress
), PRInt32(aProgressMax
),
1260 PRInt32(aTotalProgress
), PRInt32(aMaxTotalProgress
));
1263 mListenerInfoList
.Compact();
1265 // Pass the notification up to the parent...
1267 mParent
->FireOnProgressChange(aLoadInitiator
, request
,
1268 aProgress
, aProgressMax
,
1270 aTotalProgress
, aMaxTotalProgress
);
1275 void nsDocLoader::FireOnStateChange(nsIWebProgress
*aProgress
,
1276 nsIRequest
*aRequest
,
1277 PRInt32 aStateFlags
,
1281 // Remove the STATE_IS_NETWORK bit if necessary.
1283 // The rule is to remove this bit, if the notification has been passed
1284 // up from a child WebProgress, and the current WebProgress is already
1287 if (mIsLoadingDocument
&&
1288 (aStateFlags
& nsIWebProgressListener::STATE_IS_NETWORK
) &&
1289 (this != aProgress
)) {
1290 aStateFlags
&= ~nsIWebProgressListener::STATE_IS_NETWORK
;
1293 // Add the STATE_RESTORING bit if necessary.
1294 if (mIsRestoringDocument
)
1295 aStateFlags
|= nsIWebProgressListener::STATE_RESTORING
;
1298 nsCAutoString buffer
;
1300 GetURIStringFromRequest(aRequest
, buffer
);
1301 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1302 ("DocLoader:%p: Status (%s): code: %x\n",
1303 this, buffer
.get(), aStateFlags
));
1306 NS_ASSERTION(aRequest
, "Firing OnStateChange(...) notification with a NULL request!");
1309 * First notify any listeners of the new state info...
1311 * Operate the elements from back to front so that if items get
1312 * get removed from the list it won't affect our iteration
1314 nsCOMPtr
<nsIWebProgressListener
> listener
;
1315 PRInt32 count
= mListenerInfoList
.Count();
1316 PRInt32 notifyMask
= (aStateFlags
>> 16) & nsIWebProgress::NOTIFY_STATE_ALL
;
1318 while (--count
>= 0) {
1319 nsListenerInfo
*info
;
1321 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1322 if (!info
|| !(info
->mNotifyMask
& notifyMask
)) {
1326 listener
= do_QueryReferent(info
->mWeakListener
);
1328 // the listener went away. gracefully pull it out of the list.
1329 mListenerInfoList
.RemoveElementAt(count
);
1334 listener
->OnStateChange(aProgress
, aRequest
, aStateFlags
, aStatus
);
1337 mListenerInfoList
.Compact();
1339 // Pass the notification up to the parent...
1341 mParent
->FireOnStateChange(aProgress
, aRequest
, aStateFlags
, aStatus
);
1348 nsDocLoader::FireOnLocationChange(nsIWebProgress
* aWebProgress
,
1349 nsIRequest
* aRequest
,
1353 * First notify any listeners of the new state info...
1355 * Operate the elements from back to front so that if items get
1356 * get removed from the list it won't affect our iteration
1358 nsCOMPtr
<nsIWebProgressListener
> listener
;
1359 PRInt32 count
= mListenerInfoList
.Count();
1361 while (--count
>= 0) {
1362 nsListenerInfo
*info
;
1364 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1365 if (!info
|| !(info
->mNotifyMask
& nsIWebProgress::NOTIFY_LOCATION
)) {
1369 listener
= do_QueryReferent(info
->mWeakListener
);
1371 // the listener went away. gracefully pull it out of the list.
1372 mListenerInfoList
.RemoveElementAt(count
);
1377 listener
->OnLocationChange(aWebProgress
, aRequest
, aUri
);
1380 mListenerInfoList
.Compact();
1382 // Pass the notification up to the parent...
1384 mParent
->FireOnLocationChange(aWebProgress
, aRequest
, aUri
);
1389 nsDocLoader::FireOnStatusChange(nsIWebProgress
* aWebProgress
,
1390 nsIRequest
* aRequest
,
1392 const PRUnichar
* aMessage
)
1395 * First notify any listeners of the new state info...
1397 * Operate the elements from back to front so that if items get
1398 * get removed from the list it won't affect our iteration
1400 nsCOMPtr
<nsIWebProgressListener
> listener
;
1401 PRInt32 count
= mListenerInfoList
.Count();
1403 while (--count
>= 0) {
1404 nsListenerInfo
*info
;
1406 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1407 if (!info
|| !(info
->mNotifyMask
& nsIWebProgress::NOTIFY_STATUS
)) {
1411 listener
= do_QueryReferent(info
->mWeakListener
);
1413 // the listener went away. gracefully pull it out of the list.
1414 mListenerInfoList
.RemoveElementAt(count
);
1419 listener
->OnStatusChange(aWebProgress
, aRequest
, aStatus
, aMessage
);
1421 mListenerInfoList
.Compact();
1423 // Pass the notification up to the parent...
1425 mParent
->FireOnStatusChange(aWebProgress
, aRequest
, aStatus
, aMessage
);
1430 nsDocLoader::RefreshAttempted(nsIWebProgress
* aWebProgress
,
1436 * Returns true if the refresh may proceed,
1437 * false if the refresh should be blocked.
1439 * First notify any listeners of the refresh attempt...
1441 * Iterate the elements from back to front so that if items
1442 * get removed from the list it won't affect our iteration
1444 PRBool allowRefresh
= PR_TRUE
;
1445 PRInt32 count
= mListenerInfoList
.Count();
1447 while (--count
>= 0) {
1448 nsListenerInfo
*info
;
1450 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1451 if (!info
|| !(info
->mNotifyMask
& nsIWebProgress::NOTIFY_REFRESH
)) {
1455 nsCOMPtr
<nsIWebProgressListener
> listener
=
1456 do_QueryReferent(info
->mWeakListener
);
1458 // the listener went away. gracefully pull it out of the list.
1459 mListenerInfoList
.RemoveElementAt(count
);
1464 nsCOMPtr
<nsIWebProgressListener2
> listener2
=
1465 do_QueryReferent(info
->mWeakListener
);
1469 PRBool listenerAllowedRefresh
;
1470 nsresult listenerRV
= listener2
->OnRefreshAttempted(
1471 aWebProgress
, aURI
, aDelay
, aSameURI
, &listenerAllowedRefresh
);
1472 if (NS_FAILED(listenerRV
))
1475 allowRefresh
= allowRefresh
&& listenerAllowedRefresh
;
1478 mListenerInfoList
.Compact();
1480 // Pass the notification up to the parent...
1482 allowRefresh
= allowRefresh
&&
1483 mParent
->RefreshAttempted(aWebProgress
, aURI
, aDelay
, aSameURI
);
1486 return allowRefresh
;
1490 nsDocLoader::GetListenerInfo(nsIWebProgressListener
*aListener
)
1493 nsListenerInfo
*info
;
1495 nsCOMPtr
<nsISupports
> listener1
= do_QueryInterface(aListener
);
1496 count
= mListenerInfoList
.Count();
1497 for (i
=0; i
<count
; i
++) {
1498 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(i
));
1500 NS_ASSERTION(info
, "There should NEVER be a null listener in the list");
1502 nsCOMPtr
<nsISupports
> listener2
= do_QueryReferent(info
->mWeakListener
);
1503 if (listener1
== listener2
)
1510 nsresult
nsDocLoader::AddRequestInfo(nsIRequest
*aRequest
)
1512 if (!PL_DHashTableOperate(&mRequestInfoHash
, aRequest
, PL_DHASH_ADD
)) {
1513 return NS_ERROR_OUT_OF_MEMORY
;
1519 void nsDocLoader::RemoveRequestInfo(nsIRequest
*aRequest
)
1521 PL_DHashTableOperate(&mRequestInfoHash
, aRequest
, PL_DHASH_REMOVE
);
1524 nsRequestInfo
* nsDocLoader::GetRequestInfo(nsIRequest
*aRequest
)
1526 nsRequestInfo
*info
=
1527 static_cast<nsRequestInfo
*>
1528 (PL_DHashTableOperate(&mRequestInfoHash
, aRequest
,
1531 if (PL_DHASH_ENTRY_IS_FREE(info
)) {
1532 // Nothing found in the hash, return null.
1537 // Return what we found in the hash...
1542 // PLDHashTable enumeration callback that just removes every entry
1544 static PLDHashOperator
1545 RemoveInfoCallback(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
, PRUint32 number
,
1548 return PL_DHASH_REMOVE
;
1551 void nsDocLoader::ClearRequestInfoHash(void)
1553 if (!mRequestInfoHash
.ops
|| !mRequestInfoHash
.entryCount
) {
1554 // No hash, or the hash is empty, nothing to do here then...
1559 PL_DHashTableEnumerate(&mRequestInfoHash
, RemoveInfoCallback
, nsnull
);
1562 // PLDHashTable enumeration callback that calculates the max progress.
1563 static PLDHashOperator
1564 CalcMaxProgressCallback(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
1565 PRUint32 number
, void *arg
)
1567 const nsRequestInfo
*info
= static_cast<const nsRequestInfo
*>(hdr
);
1568 nsInt64
*max
= static_cast<nsInt64
*>(arg
);
1570 if (info
->mMaxProgress
< info
->mCurrentProgress
) {
1573 return PL_DHASH_STOP
;
1576 *max
+= info
->mMaxProgress
;
1578 return PL_DHASH_NEXT
;
1581 PRInt64
nsDocLoader::CalculateMaxProgress()
1583 nsInt64 max
= mCompletedTotalProgress
;
1584 PL_DHashTableEnumerate(&mRequestInfoHash
, CalcMaxProgressCallback
, &max
);
1588 NS_IMETHODIMP
nsDocLoader::AsyncOnChannelRedirect(nsIChannel
*aOldChannel
,
1589 nsIChannel
*aNewChannel
,
1591 nsIAsyncVerifyRedirectCallback
*cb
)
1595 nsLoadFlags loadFlags
= 0;
1596 PRInt32 stateFlags
= nsIWebProgressListener::STATE_REDIRECTING
|
1597 nsIWebProgressListener::STATE_IS_REQUEST
;
1599 aOldChannel
->GetLoadFlags(&loadFlags
);
1600 // If the document channel is being redirected, then indicate that the
1601 // document is being redirected in the notification...
1602 if (loadFlags
& nsIChannel::LOAD_DOCUMENT_URI
)
1604 stateFlags
|= nsIWebProgressListener::STATE_IS_DOCUMENT
;
1607 nsCOMPtr
<nsIRequest
> request(do_QueryInterface(aOldChannel
));
1608 NS_ASSERTION(request
== mDocumentRequest
, "Wrong Document Channel");
1612 OnRedirectStateChange(aOldChannel
, aNewChannel
, aFlags
, stateFlags
);
1613 FireOnStateChange(this, aOldChannel
, stateFlags
, NS_OK
);
1616 cb
->OnRedirectVerifyCallback(NS_OK
);
1621 * Implementation of nsISecurityEventSink method...
1624 NS_IMETHODIMP
nsDocLoader::OnSecurityChange(nsISupports
* aContext
,
1628 // Fire progress notifications out to any registered nsIWebProgressListeners.
1631 nsCOMPtr
<nsIRequest
> request
= do_QueryInterface(aContext
);
1632 nsIWebProgress
* webProgress
= static_cast<nsIWebProgress
*>(this);
1635 * First notify any listeners of the new state info...
1637 * Operate the elements from back to front so that if items get
1638 * get removed from the list it won't affect our iteration
1640 nsCOMPtr
<nsIWebProgressListener
> listener
;
1641 PRInt32 count
= mListenerInfoList
.Count();
1643 while (--count
>= 0) {
1644 nsListenerInfo
*info
;
1646 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1647 if (!info
|| !(info
->mNotifyMask
& nsIWebProgress::NOTIFY_SECURITY
)) {
1651 listener
= do_QueryReferent(info
->mWeakListener
);
1653 // the listener went away. gracefully pull it out of the list.
1654 mListenerInfoList
.RemoveElementAt(count
);
1659 listener
->OnSecurityChange(webProgress
, request
, aState
);
1662 mListenerInfoList
.Compact();
1664 // Pass the notification up to the parent...
1666 mParent
->OnSecurityChange(aContext
, aState
);
1672 * Implementation of nsISupportsPriority methods...
1674 * The priority of the DocLoader _is_ the priority of its LoadGroup.
1676 * XXX(darin): Once we start storing loadgroups in loadgroups, this code will
1680 NS_IMETHODIMP
nsDocLoader::GetPriority(PRInt32
*aPriority
)
1682 nsCOMPtr
<nsISupportsPriority
> p
= do_QueryInterface(mLoadGroup
);
1684 return p
->GetPriority(aPriority
);
1690 NS_IMETHODIMP
nsDocLoader::SetPriority(PRInt32 aPriority
)
1692 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1693 ("DocLoader:%p: SetPriority(%d) called\n", this, aPriority
));
1695 nsCOMPtr
<nsISupportsPriority
> p
= do_QueryInterface(mLoadGroup
);
1697 p
->SetPriority(aPriority
);
1699 PRInt32 count
= mChildList
.Count();
1701 nsDocLoader
*loader
;
1702 for (PRInt32 i
=0; i
< count
; i
++) {
1703 loader
= static_cast<nsDocLoader
*>(ChildAt(i
));
1705 loader
->SetPriority(aPriority
);
1712 NS_IMETHODIMP
nsDocLoader::AdjustPriority(PRInt32 aDelta
)
1714 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1715 ("DocLoader:%p: AdjustPriority(%d) called\n", this, aDelta
));
1717 nsCOMPtr
<nsISupportsPriority
> p
= do_QueryInterface(mLoadGroup
);
1719 p
->AdjustPriority(aDelta
);
1721 PRInt32 count
= mChildList
.Count();
1723 nsDocLoader
*loader
;
1724 for (PRInt32 i
=0; i
< count
; i
++) {
1725 loader
= static_cast<nsDocLoader
*>(ChildAt(i
));
1727 loader
->AdjustPriority(aDelta
);
1738 void nsDocLoader::DumpChannelInfo()
1740 nsChannelInfo
*info
;
1742 PRInt32 current
=0, max
=0;
1745 printf("==== DocLoader=%x\n", this);
1747 count
= mChannelInfoList
.Count();
1748 for(i
=0; i
<count
; i
++) {
1749 info
= (nsChannelInfo
*)mChannelInfoList
.ElementAt(i
);
1752 nsCAutoString buffer
;
1753 nsresult rv
= NS_OK
;
1755 rv
= info
->mURI
->GetSpec(buffer
);
1758 printf(" [%d] current=%d max=%d [%s]\n", i
,
1759 info
->mCurrentProgress
,
1760 info
->mMaxProgress
, buffer
.get());
1763 current
+= info
->mCurrentProgress
;
1765 if (info
->mMaxProgress
< info
->mCurrentProgress
) {
1768 max
+= info
->mMaxProgress
;
1773 printf("\nCurrent=%d Total=%d\n====\n", current
, max
);