1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "nsDocLoader.h"
10 #include "nsCURILoader.h"
11 #include "nsNetUtil.h"
12 #include "nsIHttpChannel.h"
13 #include "nsIWebProgressListener2.h"
15 #include "nsIServiceManager.h"
16 #include "nsXPIDLString.h"
21 #include "nsWeakPtr.h"
22 #include "nsAutoPtr.h"
24 #include "nsIDOMWindow.h"
26 #include "nsIStringBundle.h"
27 #include "nsIScriptSecurityManager.h"
29 #include "nsITransport.h"
30 #include "nsISocketTransport.h"
32 #include "nsIDOMDocument.h"
33 #include "nsIDocument.h"
34 #include "nsPresContext.h"
35 #include "nsIAsyncVerifyRedirectCallback.h"
37 static NS_DEFINE_CID(kThisImplCID
, NS_THIS_DOCLOADER_IMPL_CID
);
39 #if defined(PR_LOGGING)
41 // Log module for nsIDocumentLoader logging...
43 // To enable logging (see prlog.h for full details):
45 // set NSPR_LOG_MODULES=DocLoader:5
46 // set NSPR_LOG_FILE=nspr.log
48 // this enables PR_LOG_DEBUG level information and places all output in
51 PRLogModuleInfo
* gDocLoaderLog
= nullptr;
52 #endif /* PR_LOGGING */
56 void GetURIStringFromRequest(nsIRequest
* request
, nsACString
&name
)
59 request
->GetName(name
);
61 name
.AssignLiteral("???");
68 nsDocLoader::RequestInfoHashInitEntry(PLDHashTable
* table
,
69 PLDHashEntryHdr
* entry
,
72 // Initialize the entry with placement new
73 new (entry
) nsRequestInfo(key
);
78 nsDocLoader::RequestInfoHashClearEntry(PLDHashTable
* table
,
79 PLDHashEntryHdr
* entry
)
81 nsRequestInfo
* info
= static_cast<nsRequestInfo
*>(entry
);
82 info
->~nsRequestInfo();
85 struct nsListenerInfo
{
86 nsListenerInfo(nsIWeakReference
*aListener
, unsigned long aNotifyMask
)
87 : mWeakListener(aListener
),
88 mNotifyMask(aNotifyMask
)
92 // Weak pointer for the nsIWebProgressListener...
93 nsWeakPtr mWeakListener
;
95 // Mask indicating which notifications the listener wants to receive.
96 unsigned long mNotifyMask
;
100 nsDocLoader::nsDocLoader()
102 mListenerInfoList(8),
103 mCurrentSelfProgress(0),
105 mCurrentTotalProgress(0),
106 mMaxTotalProgress(0),
107 mCompletedTotalProgress(0),
108 mIsLoadingDocument(false),
109 mIsRestoringDocument(false),
110 mDontFlushLayout(false),
111 mIsFlushingLayout(false)
113 #if defined(PR_LOGGING)
114 if (nullptr == gDocLoaderLog
) {
115 gDocLoaderLog
= PR_NewLogModule("DocLoader");
117 #endif /* PR_LOGGING */
119 static const PLDHashTableOps hash_table_ops
=
123 PL_DHashVoidPtrKeyStub
,
124 PL_DHashMatchEntryStub
,
125 PL_DHashMoveEntryStub
,
126 RequestInfoHashClearEntry
,
127 PL_DHashFinalizeStub
,
128 RequestInfoHashInitEntry
131 if (!PL_DHashTableInit(&mRequestInfoHash
, &hash_table_ops
, nullptr,
132 sizeof(nsRequestInfo
), 16)) {
133 mRequestInfoHash
.ops
= nullptr;
136 ClearInternalProgress();
138 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
139 ("DocLoader:%p: created.\n", this));
143 nsDocLoader::SetDocLoaderParent(nsDocLoader
*aParent
)
152 if (!mRequestInfoHash
.ops
) {
153 return NS_ERROR_OUT_OF_MEMORY
;
156 nsresult rv
= NS_NewLoadGroup(getter_AddRefs(mLoadGroup
), this);
157 if (NS_FAILED(rv
)) return rv
;
159 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
160 ("DocLoader:%p: load group %x.\n", this, mLoadGroup
.get()));
165 nsDocLoader::~nsDocLoader()
168 |ClearWeakReferences()| here is intended to prevent people holding weak references
169 from re-entering this destructor since |QueryReferent()| will |AddRef()| me, and the
170 subsequent |Release()| will try to destroy me. At this point there should be only
171 weak references remaining (otherwise, we wouldn't be getting destroyed).
173 An alternative would be incrementing our refcount (consider it a compressed flag
174 saying "Don't re-destroy."). I haven't yet decided which is better. [scc]
176 // XXXbz now that NS_IMPL_RELEASE stabilizes by setting refcount to 1, is
178 ClearWeakReferences();
182 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
183 ("DocLoader:%p: deleted.\n", this));
185 if (mRequestInfoHash
.ops
) {
186 PL_DHashTableFinish(&mRequestInfoHash
);
192 * Implementation of ISupports methods...
194 NS_IMPL_ADDREF(nsDocLoader
)
195 NS_IMPL_RELEASE(nsDocLoader
)
197 NS_INTERFACE_MAP_BEGIN(nsDocLoader
)
198 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIRequestObserver
)
199 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver
)
200 NS_INTERFACE_MAP_ENTRY(nsIDocumentLoader
)
201 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
202 NS_INTERFACE_MAP_ENTRY(nsIWebProgress
)
203 NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink
)
204 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
205 NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink
)
206 NS_INTERFACE_MAP_ENTRY(nsISecurityEventSink
)
207 NS_INTERFACE_MAP_ENTRY(nsISupportsPriority
)
208 if (aIID
.Equals(kThisImplCID
))
209 foundInterface
= static_cast<nsIDocumentLoader
*>(this);
215 * Implementation of nsIInterfaceRequestor methods...
217 NS_IMETHODIMP
nsDocLoader::GetInterface(const nsIID
& aIID
, void** aSink
)
219 nsresult rv
= NS_ERROR_NO_INTERFACE
;
221 NS_ENSURE_ARG_POINTER(aSink
);
223 if(aIID
.Equals(NS_GET_IID(nsILoadGroup
))) {
225 NS_IF_ADDREF((nsISupports
*)*aSink
);
228 rv
= QueryInterface(aIID
, aSink
);
235 already_AddRefed
<nsDocLoader
>
236 nsDocLoader::GetAsDocLoader(nsISupports
* aSupports
)
238 nsRefPtr
<nsDocLoader
> ret
= do_QueryObject(aSupports
);
244 nsDocLoader::AddDocLoaderAsChildOfRoot(nsDocLoader
* aDocLoader
)
247 nsCOMPtr
<nsIDocumentLoader
> docLoaderService
=
248 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID
, &rv
);
249 NS_ENSURE_SUCCESS(rv
, rv
);
251 nsRefPtr
<nsDocLoader
> rootDocLoader
= GetAsDocLoader(docLoaderService
);
252 NS_ENSURE_TRUE(rootDocLoader
, NS_ERROR_UNEXPECTED
);
254 return rootDocLoader
->AddChildLoader(aDocLoader
);
258 nsDocLoader::Stop(void)
262 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
263 ("DocLoader:%p: Stop() called\n", this));
265 NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList
, nsDocLoader
, Stop
, ());
268 rv
= mLoadGroup
->Cancel(NS_BINDING_ABORTED
);
270 // Don't report that we're flushing layout so IsBusy returns false after a
272 mIsFlushingLayout
= false;
274 // Clear out mChildrenInOnload. We want to make sure to fire our
275 // onload at this point, and there's no issue with mChildrenInOnload
276 // after this, since mDocumentRequest will be null after the
277 // DocLoaderIsEmpty() call.
278 mChildrenInOnload
.Clear();
280 // Make sure to call DocLoaderIsEmpty now so that we reset mDocumentRequest,
281 // etc, as needed. We could be getting into here from a subframe onload, in
282 // which case the call to DocLoaderIsEmpty() is coming but hasn't quite
283 // happened yet, Canceling the loadgroup did nothing (because it was already
284 // empty), and we're about to start a new load (which is what triggered this
287 // XXXbz If the child frame loadgroups were requests in mLoadgroup, I suspect
288 // we wouldn't need the call here....
290 NS_ASSERTION(!IsBusy(), "Shouldn't be busy here");
291 DocLoaderIsEmpty(false);
298 nsDocLoader::IsBusy()
303 // A document loader is busy if either:
305 // 1. One of its children is in the middle of an onload handler. Note that
306 // the handler may have already removed this child from mChildList!
307 // 2. It is currently loading a document and either has parts of it still
308 // loading, or has a busy child docloader.
309 // 3. It's currently flushing layout in DocLoaderIsEmpty().
312 if (mChildrenInOnload
.Count() || mIsFlushingLayout
) {
316 /* Is this document loader busy? */
317 if (!mIsLoadingDocument
) {
322 rv
= mLoadGroup
->IsPending(&busy
);
330 /* check its child document loaders... */
331 uint32_t count
= mChildList
.Length();
332 for (uint32_t i
=0; i
< count
; i
++) {
333 nsIDocumentLoader
* loader
= ChildAt(i
);
335 // This is a safe cast, because we only put nsDocLoader objects into the
337 if (loader
&& static_cast<nsDocLoader
*>(loader
)->IsBusy())
345 nsDocLoader::GetContainer(nsISupports
** aResult
)
347 NS_ADDREF(*aResult
= static_cast<nsIDocumentLoader
*>(this));
353 nsDocLoader::GetLoadGroup(nsILoadGroup
** aResult
)
357 if (nullptr == aResult
) {
358 rv
= NS_ERROR_NULL_POINTER
;
360 *aResult
= mLoadGroup
;
361 NS_IF_ADDREF(*aResult
);
367 nsDocLoader::Destroy()
371 // Remove the document loader from the parent list of loaders...
374 mParent
->RemoveChildLoader(this);
377 // Release all the information about network requests...
378 ClearRequestInfoHash();
380 // Release all the information about registered listeners...
381 int32_t count
= mListenerInfoList
.Count();
382 for(int32_t i
= 0; i
< count
; i
++) {
383 nsListenerInfo
*info
=
384 static_cast<nsListenerInfo
*>(mListenerInfoList
.ElementAt(i
));
389 mListenerInfoList
.Clear();
390 mListenerInfoList
.Compact();
392 mDocumentRequest
= 0;
395 mLoadGroup
->SetGroupObserver(nullptr);
401 nsDocLoader::DestroyChildren()
403 uint32_t count
= mChildList
.Length();
404 // if the doc loader still has children...we need to enumerate the
405 // children and make them null out their back ptr to the parent doc
407 for (uint32_t i
=0; i
< count
; i
++)
409 nsIDocumentLoader
* loader
= ChildAt(i
);
412 // This is a safe cast, as we only put nsDocLoader objects into the
414 static_cast<nsDocLoader
*>(loader
)->SetDocLoaderParent(nullptr);
421 nsDocLoader::OnStartRequest(nsIRequest
*request
, nsISupports
*aCtxt
)
423 // called each time a request is added to the group.
426 if (PR_LOG_TEST(gDocLoaderLog
, PR_LOG_DEBUG
)) {
428 request
->GetName(name
);
432 mLoadGroup
->GetActiveCount(&count
);
434 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
435 ("DocLoader:%p: OnStartRequest[%p](%s) mIsLoadingDocument=%s, %u active URLs",
436 this, request
, name
.get(),
437 (mIsLoadingDocument
? "true" : "false"),
440 #endif /* PR_LOGGING */
441 bool bJustStartedLoading
= false;
443 nsLoadFlags loadFlags
= 0;
444 request
->GetLoadFlags(&loadFlags
);
446 if (!mIsLoadingDocument
&& (loadFlags
& nsIChannel::LOAD_DOCUMENT_URI
)) {
447 bJustStartedLoading
= true;
448 mIsLoadingDocument
= true;
449 ClearInternalProgress(); // only clear our progress if we are starting a new load....
453 // Create a new nsRequestInfo for the request that is starting to
456 AddRequestInfo(request
);
459 // Only fire a doStartDocumentLoad(...) if the document loader
460 // has initiated a load... Otherwise, this notification has
461 // resulted from a request being added to the load group.
463 if (mIsLoadingDocument
) {
464 if (loadFlags
& nsIChannel::LOAD_DOCUMENT_URI
) {
466 // Make sure that the document channel is null at this point...
467 // (unless its been redirected)
469 NS_ASSERTION((loadFlags
& nsIChannel::LOAD_REPLACE
) ||
470 !(mDocumentRequest
.get()),
471 "Overwriting an existing document channel!");
473 // This request is associated with the entire document...
474 mDocumentRequest
= request
;
475 mLoadGroup
->SetDefaultLoadRequest(request
);
477 // Only fire the start document load notification for the first
478 // document URI... Do not fire it again for redirections
480 if (bJustStartedLoading
) {
481 // Update the progress status state
482 mProgressStateFlags
= nsIWebProgressListener::STATE_START
;
484 // Fire the start document load notification
485 doStartDocumentLoad();
491 NS_ASSERTION(!mIsLoadingDocument
|| mDocumentRequest
,
492 "mDocumentRequest MUST be set for the duration of a page load!");
494 doStartURLLoad(request
);
500 nsDocLoader::OnStopRequest(nsIRequest
*aRequest
,
507 if (PR_LOG_TEST(gDocLoaderLog
, PR_LOG_DEBUG
)) {
509 aRequest
->GetName(name
);
513 mLoadGroup
->GetActiveCount(&count
);
515 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
516 ("DocLoader:%p: OnStopRequest[%p](%s) status=%x mIsLoadingDocument=%s, %u active URLs",
517 this, aRequest
, name
.get(),
518 aStatus
, (mIsLoadingDocument
? "true" : "false"),
523 bool bFireTransferring
= false;
526 // Set the Maximum progress to the same value as the current progress.
527 // Since the URI has finished loading, all the data is there. Also,
528 // this will allow a more accurate estimation of the max progress (in case
529 // the old value was unknown ie. -1)
531 nsRequestInfo
*info
= GetRequestInfo(aRequest
);
533 // Null out mLastStatus now so we don't find it when looking for
534 // status from now on. This destroys the nsStatusInfo and hence
535 // removes it from our list.
536 info
->mLastStatus
= nullptr;
538 int64_t oldMax
= info
->mMaxProgress
;
540 info
->mMaxProgress
= info
->mCurrentProgress
;
543 // If a request whose content-length was previously unknown has just
544 // finished loading, then use this new data to try to calculate a
545 // mMaxSelfProgress...
547 if ((oldMax
< int64_t(0)) && (mMaxSelfProgress
< int64_t(0))) {
548 mMaxSelfProgress
= CalculateMaxProgress();
551 // As we know the total progress of this request now, save it to be part
552 // of CalculateMaxProgress() result. We need to remove the info from the
553 // hash, see bug 480713.
554 mCompletedTotalProgress
+= info
->mMaxProgress
;
557 // Determine whether a STATE_TRANSFERRING notification should be
560 // If nsRequestInfo::mMaxProgress (as stored in oldMax) and
561 // nsRequestInfo::mCurrentProgress are both 0, then the
562 // STATE_TRANSFERRING notification has not been fired yet...
564 if ((oldMax
== 0) && (info
->mCurrentProgress
== 0)) {
565 nsCOMPtr
<nsIChannel
> channel(do_QueryInterface(aRequest
));
567 // Only fire a TRANSFERRING notification if the request is also a
568 // channel -- data transfer requires a nsIChannel!
571 if (NS_SUCCEEDED(aStatus
)) {
572 bFireTransferring
= true;
575 // If the request failed (for any reason other than being
576 // redirected or retargeted), the TRANSFERRING notification can
577 // still be fired if a HTTP connection was established to a server.
579 else if (aStatus
!= NS_BINDING_REDIRECTED
&&
580 aStatus
!= NS_BINDING_RETARGETED
) {
582 // Only if the load has been targeted (see bug 268483)...
585 channel
->GetLoadFlags(&lf
);
586 if (lf
& nsIChannel::LOAD_TARGETED
) {
587 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aRequest
));
589 uint32_t responseCode
;
590 rv
= httpChannel
->GetResponseStatus(&responseCode
);
591 if (NS_SUCCEEDED(rv
)) {
593 // A valid server status indicates that a connection was
594 // established to the server... So, fire the notification
595 // even though a failure occurred later...
597 bFireTransferring
= true;
606 if (bFireTransferring
) {
607 // Send a STATE_TRANSFERRING notification for the request.
610 flags
= nsIWebProgressListener::STATE_TRANSFERRING
|
611 nsIWebProgressListener::STATE_IS_REQUEST
;
613 // Move the WebProgress into the STATE_TRANSFERRING state if necessary...
615 if (mProgressStateFlags
& nsIWebProgressListener::STATE_START
) {
616 mProgressStateFlags
= nsIWebProgressListener::STATE_TRANSFERRING
;
618 // Send STATE_TRANSFERRING for the document too...
619 flags
|= nsIWebProgressListener::STATE_IS_DOCUMENT
;
622 FireOnStateChange(this, aRequest
, flags
, NS_OK
);
626 // Fire the OnStateChange(...) notification for stop request
628 doStopURLLoad(aRequest
, aStatus
);
630 // Clear this request out of the hash to avoid bypass of FireOnStateChange
631 // when address of the request is reused.
632 RemoveRequestInfo(aRequest
);
635 // Only fire the DocLoaderIsEmpty(...) if the document loader has initiated a
636 // load. This will handle removing the request from our hashtable as needed.
638 if (mIsLoadingDocument
) {
639 DocLoaderIsEmpty(true);
646 nsresult
nsDocLoader::RemoveChildLoader(nsDocLoader
* aChild
)
648 nsresult rv
= mChildList
.RemoveElement(aChild
) ? NS_OK
: NS_ERROR_FAILURE
;
649 if (NS_SUCCEEDED(rv
)) {
650 aChild
->SetDocLoaderParent(nullptr);
655 nsresult
nsDocLoader::AddChildLoader(nsDocLoader
* aChild
)
657 nsresult rv
= mChildList
.AppendElement(aChild
) ? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
658 if (NS_SUCCEEDED(rv
)) {
659 aChild
->SetDocLoaderParent(this);
664 NS_IMETHODIMP
nsDocLoader::GetDocumentChannel(nsIChannel
** aChannel
)
666 if (!mDocumentRequest
) {
671 return CallQueryInterface(mDocumentRequest
, aChannel
);
675 void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout
)
677 if (mIsLoadingDocument
) {
678 /* In the unimagineably rude circumstance that onload event handlers
679 triggered by this function actually kill the window ... ok, it's
680 not unimagineable; it's happened ... this deathgrip keeps this object
681 alive long enough to survive this function call. */
682 nsCOMPtr
<nsIDocumentLoader
> kungFuDeathGrip(this);
684 // Don't flush layout if we're still busy.
689 NS_ASSERTION(!mIsFlushingLayout
, "Someone screwed up");
691 // The load group for this DocumentLoader is idle. Flush if we need to.
692 if (aFlushLayout
&& !mDontFlushLayout
) {
693 nsCOMPtr
<nsIDOMDocument
> domDoc
= do_GetInterface(GetAsSupports(this));
694 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
696 // We start loads from style resolution, so we need to flush out style
697 // no matter what. If we have user fonts, we also need to flush layout,
698 // since the reflow is what starts font loads.
699 mozFlushType flushType
= Flush_Style
;
700 nsIPresShell
* shell
= doc
->GetShell();
702 // Be safe in case this presshell is in teardown now
703 nsPresContext
* presContext
= shell
->GetPresContext();
704 if (presContext
&& presContext
->GetUserFontSet()) {
705 flushType
= Flush_Layout
;
708 mDontFlushLayout
= mIsFlushingLayout
= true;
709 doc
->FlushPendingNotifications(flushType
);
710 mDontFlushLayout
= mIsFlushingLayout
= false;
714 // And now check whether we're really busy; that might have changed with
717 // Clear out our request info hash, now that our load really is done and
718 // we don't need it anymore to CalculateMaxProgress().
719 ClearInternalProgress();
721 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
722 ("DocLoader:%p: Is now idle...\n", this));
724 nsCOMPtr
<nsIRequest
> docRequest
= mDocumentRequest
;
726 NS_ASSERTION(mDocumentRequest
, "No Document Request!");
727 mDocumentRequest
= 0;
728 mIsLoadingDocument
= false;
730 // Update the progress status state - the document is done
731 mProgressStateFlags
= nsIWebProgressListener::STATE_STOP
;
734 nsresult loadGroupStatus
= NS_OK
;
735 mLoadGroup
->GetStatus(&loadGroupStatus
);
738 // New code to break the circular reference between
739 // the load group and the docloader...
741 mLoadGroup
->SetDefaultLoadRequest(nullptr);
743 // Take a ref to our parent now so that we can call DocLoaderIsEmpty() on
744 // it even if our onload handler removes us from the docloader tree.
745 nsRefPtr
<nsDocLoader
> parent
= mParent
;
747 // Note that if calling ChildEnteringOnload() on the parent returns false
748 // then calling our onload handler is not safe. That can only happen on
749 // OOM, so that's ok.
750 if (!parent
|| parent
->ChildEnteringOnload(this)) {
751 // Do nothing with our state after firing the
752 // OnEndDocumentLoad(...). The document loader may be loading a *new*
753 // document - if LoadDocument() was called from a handler!
755 doStopDocumentLoad(docRequest
, loadGroupStatus
);
758 parent
->ChildDoneWithOnload(this);
765 void nsDocLoader::doStartDocumentLoad(void)
769 nsAutoCString buffer
;
771 GetURIStringFromRequest(mDocumentRequest
, buffer
);
772 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
773 ("DocLoader:%p: ++ Firing OnStateChange for start document load (...)."
775 this, buffer
.get()));
778 // Fire an OnStatus(...) notification STATE_START. This indicates
779 // that the document represented by mDocumentRequest has started to
781 FireOnStateChange(this,
783 nsIWebProgressListener::STATE_START
|
784 nsIWebProgressListener::STATE_IS_DOCUMENT
|
785 nsIWebProgressListener::STATE_IS_REQUEST
|
786 nsIWebProgressListener::STATE_IS_WINDOW
|
787 nsIWebProgressListener::STATE_IS_NETWORK
,
791 void nsDocLoader::doStartURLLoad(nsIRequest
*request
)
794 nsAutoCString buffer
;
796 GetURIStringFromRequest(request
, buffer
);
797 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
798 ("DocLoader:%p: ++ Firing OnStateChange start url load (...)."
800 this, buffer
.get()));
803 FireOnStateChange(this,
805 nsIWebProgressListener::STATE_START
|
806 nsIWebProgressListener::STATE_IS_REQUEST
,
810 void nsDocLoader::doStopURLLoad(nsIRequest
*request
, nsresult aStatus
)
813 nsAutoCString buffer
;
815 GetURIStringFromRequest(request
, buffer
);
816 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
817 ("DocLoader:%p: ++ Firing OnStateChange for end url load (...)."
818 "\tURI: %s status=%x\n",
819 this, buffer
.get(), aStatus
));
822 FireOnStateChange(this,
824 nsIWebProgressListener::STATE_STOP
|
825 nsIWebProgressListener::STATE_IS_REQUEST
,
828 // Fire a status change message for the most recent unfinished
829 // request to make sure that the displayed status is not outdated.
830 if (!mStatusInfoList
.isEmpty()) {
831 nsStatusInfo
* statusInfo
= mStatusInfoList
.getFirst();
832 FireOnStatusChange(this, statusInfo
->mRequest
,
833 statusInfo
->mStatusCode
,
834 statusInfo
->mStatusMessage
.get());
838 void nsDocLoader::doStopDocumentLoad(nsIRequest
*request
,
842 nsAutoCString buffer
;
844 GetURIStringFromRequest(request
, buffer
);
845 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
846 ("DocLoader:%p: ++ Firing OnStateChange for end document load (...)."
847 "\tURI: %s Status=%x\n",
848 this, buffer
.get(), aStatus
));
851 // Firing STATE_STOP|STATE_IS_DOCUMENT will fire onload handlers.
852 // Grab our parent chain before doing that so we can still dispatch
853 // STATE_STOP|STATE_IS_WINDW_STATE_IS_NETWORK to them all, even if
854 // the onload handlers rearrange the docshell tree.
855 WebProgressList list
;
856 GatherAncestorWebProgresses(list
);
859 // Fire an OnStateChange(...) notification indicating the the
860 // current document has finished loading...
862 int32_t flags
= nsIWebProgressListener::STATE_STOP
|
863 nsIWebProgressListener::STATE_IS_DOCUMENT
;
864 for (uint32_t i
= 0; i
< list
.Length(); ++i
) {
865 list
[i
]->DoFireOnStateChange(this, request
, flags
, aStatus
);
869 // Fire a final OnStateChange(...) notification indicating the the
870 // current document has finished loading...
872 flags
= nsIWebProgressListener::STATE_STOP
|
873 nsIWebProgressListener::STATE_IS_WINDOW
|
874 nsIWebProgressListener::STATE_IS_NETWORK
;
875 for (uint32_t i
= 0; i
< list
.Length(); ++i
) {
876 list
[i
]->DoFireOnStateChange(this, request
, flags
, aStatus
);
880 ////////////////////////////////////////////////////////////////////////////////////
881 // The following section contains support for nsIWebProgress and related stuff
882 ////////////////////////////////////////////////////////////////////////////////////
885 nsDocLoader::AddProgressListener(nsIWebProgressListener
*aListener
,
886 uint32_t aNotifyMask
)
890 nsListenerInfo
* info
= GetListenerInfo(aListener
);
892 // The listener is already registered!
893 return NS_ERROR_FAILURE
;
896 nsWeakPtr listener
= do_GetWeakReference(aListener
);
898 return NS_ERROR_INVALID_ARG
;
901 info
= new nsListenerInfo(listener
, aNotifyMask
);
903 return NS_ERROR_OUT_OF_MEMORY
;
906 rv
= mListenerInfoList
.AppendElement(info
) ? NS_OK
: NS_ERROR_FAILURE
;
911 nsDocLoader::RemoveProgressListener(nsIWebProgressListener
*aListener
)
915 nsListenerInfo
* info
= GetListenerInfo(aListener
);
917 rv
= mListenerInfoList
.RemoveElement(info
) ? NS_OK
: NS_ERROR_FAILURE
;
920 // The listener is not registered!
921 rv
= NS_ERROR_FAILURE
;
927 nsDocLoader::GetDOMWindow(nsIDOMWindow
**aResult
)
929 return CallGetInterface(this, aResult
);
933 nsDocLoader::GetDOMWindowID(uint64_t *aResult
)
937 nsCOMPtr
<nsIDOMWindow
> window
;
938 nsresult rv
= GetDOMWindow(getter_AddRefs(window
));
939 NS_ENSURE_SUCCESS(rv
, rv
);
941 nsCOMPtr
<nsPIDOMWindow
> piwindow
= do_QueryInterface(window
);
942 NS_ENSURE_STATE(piwindow
);
944 MOZ_ASSERT(piwindow
->IsOuterWindow());
945 *aResult
= piwindow
->WindowID();
950 nsDocLoader::GetIsTopLevel(bool *aResult
)
954 nsCOMPtr
<nsIDOMWindow
> window
;
955 GetDOMWindow(getter_AddRefs(window
));
957 nsCOMPtr
<nsPIDOMWindow
> piwindow
= do_QueryInterface(window
);
958 NS_ENSURE_STATE(piwindow
);
960 nsCOMPtr
<nsIDOMWindow
> topWindow
;
961 nsresult rv
= piwindow
->GetTop(getter_AddRefs(topWindow
));
962 NS_ENSURE_SUCCESS(rv
, rv
);
964 *aResult
= piwindow
== topWindow
;
971 nsDocLoader::GetIsLoadingDocument(bool *aIsLoadingDocument
)
973 *aIsLoadingDocument
= mIsLoadingDocument
;
979 nsDocLoader::GetLoadType(uint32_t *aLoadType
)
983 return NS_ERROR_NOT_IMPLEMENTED
;
986 int64_t nsDocLoader::GetMaxTotalProgress()
988 int64_t newMaxTotal
= 0;
990 uint32_t count
= mChildList
.Length();
991 nsCOMPtr
<nsIWebProgress
> webProgress
;
992 for (uint32_t i
=0; i
< count
; i
++)
994 int64_t individualProgress
= 0;
995 nsIDocumentLoader
* docloader
= ChildAt(i
);
998 // Cast is safe since all children are nsDocLoader too
999 individualProgress
= ((nsDocLoader
*) docloader
)->GetMaxTotalProgress();
1001 if (individualProgress
< int64_t(0)) // if one of the elements doesn't know it's size
1002 // then none of them do
1004 newMaxTotal
= int64_t(-1);
1008 newMaxTotal
+= individualProgress
;
1011 int64_t progress
= -1;
1012 if (mMaxSelfProgress
>= int64_t(0) && newMaxTotal
>= int64_t(0))
1013 progress
= newMaxTotal
+ mMaxSelfProgress
;
1018 ////////////////////////////////////////////////////////////////////////////////////
1019 // The following section contains support for nsIProgressEventSink which is used to
1020 // pass progress and status between the actual request and the doc loader. The doc loader
1021 // then turns around and makes the right web progress calls based on this information.
1022 ////////////////////////////////////////////////////////////////////////////////////
1024 NS_IMETHODIMP
nsDocLoader::OnProgress(nsIRequest
*aRequest
, nsISupports
* ctxt
,
1025 uint64_t aProgress
, uint64_t aProgressMax
)
1027 nsRequestInfo
*info
;
1028 int64_t progressDelta
= 0;
1031 // Update the RequestInfo entry with the new progress data
1033 info
= GetRequestInfo(aRequest
);
1035 // suppress sending STATE_TRANSFERRING if this is upload progress (see bug 240053)
1036 if (!info
->mUploading
&& (int64_t(0) == info
->mCurrentProgress
) && (int64_t(0) == info
->mMaxProgress
)) {
1038 // If we receive an OnProgress event from a toplevel channel that the URI Loader
1039 // has not yet targeted, then we must suppress the event. This is necessary to
1040 // ensure that webprogresslisteners do not get confused when the channel is
1041 // finally targeted. See bug 257308.
1044 aRequest
->GetLoadFlags(&lf
);
1045 if ((lf
& nsIChannel::LOAD_DOCUMENT_URI
) && !(lf
& nsIChannel::LOAD_TARGETED
)) {
1046 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1047 ("DocLoader:%p Ignoring OnProgress while load is not targeted\n", this));
1052 // This is the first progress notification for the entry. If
1053 // (aMaxProgress > 0) then the content-length of the data is known,
1054 // so update mMaxSelfProgress... Otherwise, set it to -1 to indicate
1055 // that the content-length is no longer known.
1057 if (uint64_t(aProgressMax
) != UINT64_MAX
) {
1058 mMaxSelfProgress
+= int64_t(aProgressMax
);
1059 info
->mMaxProgress
= int64_t(aProgressMax
);
1061 mMaxSelfProgress
= int64_t(-1);
1062 info
->mMaxProgress
= int64_t(-1);
1065 // Send a STATE_TRANSFERRING notification for the request.
1068 flags
= nsIWebProgressListener::STATE_TRANSFERRING
|
1069 nsIWebProgressListener::STATE_IS_REQUEST
;
1071 // Move the WebProgress into the STATE_TRANSFERRING state if necessary...
1073 if (mProgressStateFlags
& nsIWebProgressListener::STATE_START
) {
1074 mProgressStateFlags
= nsIWebProgressListener::STATE_TRANSFERRING
;
1076 // Send STATE_TRANSFERRING for the document too...
1077 flags
|= nsIWebProgressListener::STATE_IS_DOCUMENT
;
1080 FireOnStateChange(this, aRequest
, flags
, NS_OK
);
1083 // Update the current progress count...
1084 progressDelta
= int64_t(aProgress
) - info
->mCurrentProgress
;
1085 mCurrentSelfProgress
+= progressDelta
;
1087 info
->mCurrentProgress
= int64_t(aProgress
);
1090 // The request is not part of the load group, so ignore its progress
1095 nsAutoCString buffer
;
1097 GetURIStringFromRequest(aRequest
, buffer
);
1098 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1099 ("DocLoader:%p OOPS - No Request Info for: %s\n",
1100 this, buffer
.get()));
1107 // Fire progress notifications out to any registered nsIWebProgressListeners
1109 FireOnProgressChange(this, aRequest
, aProgress
, aProgressMax
, progressDelta
,
1110 mCurrentTotalProgress
, mMaxTotalProgress
);
1115 NS_IMETHODIMP
nsDocLoader::OnStatus(nsIRequest
* aRequest
, nsISupports
* ctxt
,
1116 nsresult aStatus
, const char16_t
* aStatusArg
)
1119 // Fire progress notifications out to any registered nsIWebProgressListeners
1121 if (aStatus
!= NS_OK
) {
1122 // Remember the current status for this request
1123 nsRequestInfo
*info
;
1124 info
= GetRequestInfo(aRequest
);
1126 bool uploading
= (aStatus
== NS_NET_STATUS_WRITING
||
1127 aStatus
== NS_NET_STATUS_SENDING_TO
);
1128 // If switching from uploading to downloading (or vice versa), then we
1129 // need to reset our progress counts. This is designed with HTTP form
1130 // submission in mind, where an upload is performed followed by download
1131 // of possibly several documents.
1132 if (info
->mUploading
!= uploading
) {
1133 mCurrentSelfProgress
= mMaxSelfProgress
= 0;
1134 mCurrentTotalProgress
= mMaxTotalProgress
= 0;
1135 mCompletedTotalProgress
= 0;
1136 info
->mUploading
= uploading
;
1137 info
->mCurrentProgress
= 0;
1138 info
->mMaxProgress
= 0;
1142 nsCOMPtr
<nsIStringBundleService
> sbs
=
1143 mozilla::services::GetStringBundleService();
1145 return NS_ERROR_FAILURE
;
1147 nsresult rv
= sbs
->FormatStatusMessage(aStatus
, aStatusArg
,
1148 getter_Copies(msg
));
1152 // Keep around the message. In case a request finishes, we need to make sure
1153 // to send the status message of another request to our user to that we
1154 // don't display, for example, "Transferring" messages for requests that are
1157 if (!info
->mLastStatus
) {
1158 info
->mLastStatus
= new nsStatusInfo(aRequest
);
1160 // We're going to move it to the front of the list, so remove
1161 // it from wherever it is now.
1162 info
->mLastStatus
->remove();
1164 info
->mLastStatus
->mStatusMessage
= msg
;
1165 info
->mLastStatus
->mStatusCode
= aStatus
;
1166 // Put the info at the front of the list
1167 mStatusInfoList
.insertFront(info
->mLastStatus
);
1169 FireOnStatusChange(this, aRequest
, aStatus
, msg
);
1174 void nsDocLoader::ClearInternalProgress()
1176 ClearRequestInfoHash();
1178 mCurrentSelfProgress
= mMaxSelfProgress
= 0;
1179 mCurrentTotalProgress
= mMaxTotalProgress
= 0;
1180 mCompletedTotalProgress
= 0;
1182 mProgressStateFlags
= nsIWebProgressListener::STATE_STOP
;
1186 void nsDocLoader::FireOnProgressChange(nsDocLoader
*aLoadInitiator
,
1187 nsIRequest
*request
,
1189 int64_t aProgressMax
,
1190 int64_t aProgressDelta
,
1191 int64_t aTotalProgress
,
1192 int64_t aMaxTotalProgress
)
1194 if (mIsLoadingDocument
) {
1195 mCurrentTotalProgress
+= aProgressDelta
;
1196 mMaxTotalProgress
= GetMaxTotalProgress();
1198 aTotalProgress
= mCurrentTotalProgress
;
1199 aMaxTotalProgress
= mMaxTotalProgress
;
1203 nsAutoCString buffer
;
1205 GetURIStringFromRequest(request
, buffer
);
1206 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1207 ("DocLoader:%p: Progress (%s): curSelf: %d maxSelf: %d curTotal: %d maxTotal %d\n",
1208 this, buffer
.get(), aProgress
, aProgressMax
, aTotalProgress
, aMaxTotalProgress
));
1212 * First notify any listeners of the new progress info...
1214 * Operate the elements from back to front so that if items get
1215 * get removed from the list it won't affect our iteration
1217 nsCOMPtr
<nsIWebProgressListener
> listener
;
1218 int32_t count
= mListenerInfoList
.Count();
1220 while (--count
>= 0) {
1221 nsListenerInfo
*info
;
1223 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1224 if (!info
|| !(info
->mNotifyMask
& nsIWebProgress::NOTIFY_PROGRESS
)) {
1228 listener
= do_QueryReferent(info
->mWeakListener
);
1230 // the listener went away. gracefully pull it out of the list.
1231 mListenerInfoList
.RemoveElementAt(count
);
1236 // XXX truncates 64-bit to 32-bit
1237 listener
->OnProgressChange(aLoadInitiator
,request
,
1238 int32_t(aProgress
), int32_t(aProgressMax
),
1239 int32_t(aTotalProgress
), int32_t(aMaxTotalProgress
));
1242 mListenerInfoList
.Compact();
1244 // Pass the notification up to the parent...
1246 mParent
->FireOnProgressChange(aLoadInitiator
, request
,
1247 aProgress
, aProgressMax
,
1249 aTotalProgress
, aMaxTotalProgress
);
1253 void nsDocLoader::GatherAncestorWebProgresses(WebProgressList
& aList
)
1255 for (nsDocLoader
* loader
= this; loader
; loader
= loader
->mParent
) {
1256 aList
.AppendElement(loader
);
1260 void nsDocLoader::FireOnStateChange(nsIWebProgress
*aProgress
,
1261 nsIRequest
*aRequest
,
1262 int32_t aStateFlags
,
1265 WebProgressList list
;
1266 GatherAncestorWebProgresses(list
);
1267 for (uint32_t i
= 0; i
< list
.Length(); ++i
) {
1268 list
[i
]->DoFireOnStateChange(aProgress
, aRequest
, aStateFlags
, aStatus
);
1272 void nsDocLoader::DoFireOnStateChange(nsIWebProgress
* const aProgress
,
1273 nsIRequest
* const aRequest
,
1274 int32_t &aStateFlags
,
1275 const nsresult aStatus
)
1278 // Remove the STATE_IS_NETWORK bit if necessary.
1280 // The rule is to remove this bit, if the notification has been passed
1281 // up from a child WebProgress, and the current WebProgress is already
1284 if (mIsLoadingDocument
&&
1285 (aStateFlags
& nsIWebProgressListener::STATE_IS_NETWORK
) &&
1286 (this != aProgress
)) {
1287 aStateFlags
&= ~nsIWebProgressListener::STATE_IS_NETWORK
;
1290 // Add the STATE_RESTORING bit if necessary.
1291 if (mIsRestoringDocument
)
1292 aStateFlags
|= nsIWebProgressListener::STATE_RESTORING
;
1295 nsAutoCString buffer
;
1297 GetURIStringFromRequest(aRequest
, buffer
);
1298 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1299 ("DocLoader:%p: Status (%s): code: %x\n",
1300 this, buffer
.get(), aStateFlags
));
1303 NS_ASSERTION(aRequest
, "Firing OnStateChange(...) notification with a NULL request!");
1306 * First notify any listeners of the new state info...
1308 * Operate the elements from back to front so that if items get
1309 * get removed from the list it won't affect our iteration
1311 nsCOMPtr
<nsIWebProgressListener
> listener
;
1312 int32_t count
= mListenerInfoList
.Count();
1313 int32_t notifyMask
= (aStateFlags
>> 16) & nsIWebProgress::NOTIFY_STATE_ALL
;
1315 while (--count
>= 0) {
1316 nsListenerInfo
*info
;
1318 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1319 if (!info
|| !(info
->mNotifyMask
& notifyMask
)) {
1323 listener
= do_QueryReferent(info
->mWeakListener
);
1325 // the listener went away. gracefully pull it out of the list.
1326 mListenerInfoList
.RemoveElementAt(count
);
1331 listener
->OnStateChange(aProgress
, aRequest
, aStateFlags
, aStatus
);
1334 mListenerInfoList
.Compact();
1340 nsDocLoader::FireOnLocationChange(nsIWebProgress
* aWebProgress
,
1341 nsIRequest
* aRequest
,
1346 * First notify any listeners of the new state info...
1348 * Operate the elements from back to front so that if items get
1349 * get removed from the list it won't affect our iteration
1351 nsCOMPtr
<nsIWebProgressListener
> listener
;
1352 int32_t count
= mListenerInfoList
.Count();
1354 while (--count
>= 0) {
1355 nsListenerInfo
*info
;
1357 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1358 if (!info
|| !(info
->mNotifyMask
& nsIWebProgress::NOTIFY_LOCATION
)) {
1362 listener
= do_QueryReferent(info
->mWeakListener
);
1364 // the listener went away. gracefully pull it out of the list.
1365 mListenerInfoList
.RemoveElementAt(count
);
1370 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
, ("DocLoader [%p] calling %p->OnLocationChange", this, listener
.get()));
1371 listener
->OnLocationChange(aWebProgress
, aRequest
, aUri
, aFlags
);
1374 mListenerInfoList
.Compact();
1376 // Pass the notification up to the parent...
1378 mParent
->FireOnLocationChange(aWebProgress
, aRequest
, aUri
, aFlags
);
1383 nsDocLoader::FireOnStatusChange(nsIWebProgress
* aWebProgress
,
1384 nsIRequest
* aRequest
,
1386 const char16_t
* aMessage
)
1389 * First notify any listeners of the new state info...
1391 * Operate the elements from back to front so that if items get
1392 * get removed from the list it won't affect our iteration
1394 nsCOMPtr
<nsIWebProgressListener
> listener
;
1395 int32_t count
= mListenerInfoList
.Count();
1397 while (--count
>= 0) {
1398 nsListenerInfo
*info
;
1400 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1401 if (!info
|| !(info
->mNotifyMask
& nsIWebProgress::NOTIFY_STATUS
)) {
1405 listener
= do_QueryReferent(info
->mWeakListener
);
1407 // the listener went away. gracefully pull it out of the list.
1408 mListenerInfoList
.RemoveElementAt(count
);
1413 listener
->OnStatusChange(aWebProgress
, aRequest
, aStatus
, aMessage
);
1415 mListenerInfoList
.Compact();
1417 // Pass the notification up to the parent...
1419 mParent
->FireOnStatusChange(aWebProgress
, aRequest
, aStatus
, aMessage
);
1424 nsDocLoader::RefreshAttempted(nsIWebProgress
* aWebProgress
,
1430 * Returns true if the refresh may proceed,
1431 * false if the refresh should be blocked.
1433 * First notify any listeners of the refresh attempt...
1435 * Iterate the elements from back to front so that if items
1436 * get removed from the list it won't affect our iteration
1438 bool allowRefresh
= true;
1439 int32_t count
= mListenerInfoList
.Count();
1441 while (--count
>= 0) {
1442 nsListenerInfo
*info
;
1444 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1445 if (!info
|| !(info
->mNotifyMask
& nsIWebProgress::NOTIFY_REFRESH
)) {
1449 nsCOMPtr
<nsIWebProgressListener
> listener
=
1450 do_QueryReferent(info
->mWeakListener
);
1452 // the listener went away. gracefully pull it out of the list.
1453 mListenerInfoList
.RemoveElementAt(count
);
1458 nsCOMPtr
<nsIWebProgressListener2
> listener2
=
1459 do_QueryReferent(info
->mWeakListener
);
1463 bool listenerAllowedRefresh
;
1464 nsresult listenerRV
= listener2
->OnRefreshAttempted(
1465 aWebProgress
, aURI
, aDelay
, aSameURI
, &listenerAllowedRefresh
);
1466 if (NS_FAILED(listenerRV
))
1469 allowRefresh
= allowRefresh
&& listenerAllowedRefresh
;
1472 mListenerInfoList
.Compact();
1474 // Pass the notification up to the parent...
1476 allowRefresh
= allowRefresh
&&
1477 mParent
->RefreshAttempted(aWebProgress
, aURI
, aDelay
, aSameURI
);
1480 return allowRefresh
;
1484 nsDocLoader::GetListenerInfo(nsIWebProgressListener
*aListener
)
1487 nsListenerInfo
*info
;
1489 nsCOMPtr
<nsISupports
> listener1
= do_QueryInterface(aListener
);
1490 count
= mListenerInfoList
.Count();
1491 for (i
=0; i
<count
; i
++) {
1492 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(i
));
1494 NS_ASSERTION(info
, "There should NEVER be a null listener in the list");
1496 nsCOMPtr
<nsISupports
> listener2
= do_QueryReferent(info
->mWeakListener
);
1497 if (listener1
== listener2
)
1504 nsresult
nsDocLoader::AddRequestInfo(nsIRequest
*aRequest
)
1506 if (!PL_DHashTableOperate(&mRequestInfoHash
, aRequest
, PL_DHASH_ADD
)) {
1507 return NS_ERROR_OUT_OF_MEMORY
;
1513 void nsDocLoader::RemoveRequestInfo(nsIRequest
*aRequest
)
1515 PL_DHashTableOperate(&mRequestInfoHash
, aRequest
, PL_DHASH_REMOVE
);
1518 nsDocLoader::nsRequestInfo
* nsDocLoader::GetRequestInfo(nsIRequest
* aRequest
)
1520 nsRequestInfo
* info
=
1521 static_cast<nsRequestInfo
*>
1522 (PL_DHashTableOperate(&mRequestInfoHash
, aRequest
,
1525 if (PL_DHASH_ENTRY_IS_FREE(info
)) {
1526 // Nothing found in the hash, return null.
1531 // Return what we found in the hash...
1536 // PLDHashTable enumeration callback that just removes every entry
1538 static PLDHashOperator
1539 RemoveInfoCallback(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
, uint32_t number
,
1542 return PL_DHASH_REMOVE
;
1545 void nsDocLoader::ClearRequestInfoHash(void)
1547 if (!mRequestInfoHash
.ops
|| !mRequestInfoHash
.entryCount
) {
1548 // No hash, or the hash is empty, nothing to do here then...
1553 PL_DHashTableEnumerate(&mRequestInfoHash
, RemoveInfoCallback
, nullptr);
1556 // PLDHashTable enumeration callback that calculates the max progress.
1558 nsDocLoader::CalcMaxProgressCallback(PLDHashTable
* table
, PLDHashEntryHdr
* hdr
,
1559 uint32_t number
, void* arg
)
1561 const nsRequestInfo
* info
= static_cast<const nsRequestInfo
*>(hdr
);
1562 int64_t* max
= static_cast<int64_t* >(arg
);
1564 if (info
->mMaxProgress
< info
->mCurrentProgress
) {
1567 return PL_DHASH_STOP
;
1570 *max
+= info
->mMaxProgress
;
1572 return PL_DHASH_NEXT
;
1575 int64_t nsDocLoader::CalculateMaxProgress()
1577 int64_t max
= mCompletedTotalProgress
;
1578 PL_DHashTableEnumerate(&mRequestInfoHash
, CalcMaxProgressCallback
, &max
);
1582 NS_IMETHODIMP
nsDocLoader::AsyncOnChannelRedirect(nsIChannel
*aOldChannel
,
1583 nsIChannel
*aNewChannel
,
1585 nsIAsyncVerifyRedirectCallback
*cb
)
1589 nsLoadFlags loadFlags
= 0;
1590 int32_t stateFlags
= nsIWebProgressListener::STATE_REDIRECTING
|
1591 nsIWebProgressListener::STATE_IS_REQUEST
;
1593 aOldChannel
->GetLoadFlags(&loadFlags
);
1594 // If the document channel is being redirected, then indicate that the
1595 // document is being redirected in the notification...
1596 if (loadFlags
& nsIChannel::LOAD_DOCUMENT_URI
)
1598 stateFlags
|= nsIWebProgressListener::STATE_IS_DOCUMENT
;
1601 nsCOMPtr
<nsIRequest
> request(do_QueryInterface(aOldChannel
));
1602 NS_ASSERTION(request
== mDocumentRequest
, "Wrong Document Channel");
1606 OnRedirectStateChange(aOldChannel
, aNewChannel
, aFlags
, stateFlags
);
1607 FireOnStateChange(this, aOldChannel
, stateFlags
, NS_OK
);
1610 cb
->OnRedirectVerifyCallback(NS_OK
);
1615 * Implementation of nsISecurityEventSink method...
1618 NS_IMETHODIMP
nsDocLoader::OnSecurityChange(nsISupports
* aContext
,
1622 // Fire progress notifications out to any registered nsIWebProgressListeners.
1625 nsCOMPtr
<nsIRequest
> request
= do_QueryInterface(aContext
);
1626 nsIWebProgress
* webProgress
= static_cast<nsIWebProgress
*>(this);
1629 * First notify any listeners of the new state info...
1631 * Operate the elements from back to front so that if items get
1632 * get removed from the list it won't affect our iteration
1634 nsCOMPtr
<nsIWebProgressListener
> listener
;
1635 int32_t count
= mListenerInfoList
.Count();
1637 while (--count
>= 0) {
1638 nsListenerInfo
*info
;
1640 info
= static_cast<nsListenerInfo
*>(mListenerInfoList
.SafeElementAt(count
));
1641 if (!info
|| !(info
->mNotifyMask
& nsIWebProgress::NOTIFY_SECURITY
)) {
1645 listener
= do_QueryReferent(info
->mWeakListener
);
1647 // the listener went away. gracefully pull it out of the list.
1648 mListenerInfoList
.RemoveElementAt(count
);
1653 listener
->OnSecurityChange(webProgress
, request
, aState
);
1656 mListenerInfoList
.Compact();
1658 // Pass the notification up to the parent...
1660 mParent
->OnSecurityChange(aContext
, aState
);
1666 * Implementation of nsISupportsPriority methods...
1668 * The priority of the DocLoader _is_ the priority of its LoadGroup.
1670 * XXX(darin): Once we start storing loadgroups in loadgroups, this code will
1674 NS_IMETHODIMP
nsDocLoader::GetPriority(int32_t *aPriority
)
1676 nsCOMPtr
<nsISupportsPriority
> p
= do_QueryInterface(mLoadGroup
);
1678 return p
->GetPriority(aPriority
);
1684 NS_IMETHODIMP
nsDocLoader::SetPriority(int32_t aPriority
)
1686 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1687 ("DocLoader:%p: SetPriority(%d) called\n", this, aPriority
));
1689 nsCOMPtr
<nsISupportsPriority
> p
= do_QueryInterface(mLoadGroup
);
1691 p
->SetPriority(aPriority
);
1693 NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList
, nsDocLoader
,
1694 SetPriority
, (aPriority
));
1699 NS_IMETHODIMP
nsDocLoader::AdjustPriority(int32_t aDelta
)
1701 PR_LOG(gDocLoaderLog
, PR_LOG_DEBUG
,
1702 ("DocLoader:%p: AdjustPriority(%d) called\n", this, aDelta
));
1704 nsCOMPtr
<nsISupportsPriority
> p
= do_QueryInterface(mLoadGroup
);
1706 p
->AdjustPriority(aDelta
);
1708 NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList
, nsDocLoader
,
1709 AdjustPriority
, (aDelta
));
1718 void nsDocLoader::DumpChannelInfo()
1720 nsChannelInfo
*info
;
1722 int32_t current
=0, max
=0;
1725 printf("==== DocLoader=%x\n", this);
1727 count
= mChannelInfoList
.Count();
1728 for(i
=0; i
<count
; i
++) {
1729 info
= (nsChannelInfo
*)mChannelInfoList
.ElementAt(i
);
1732 nsAutoCString buffer
;
1733 nsresult rv
= NS_OK
;
1735 rv
= info
->mURI
->GetSpec(buffer
);
1738 printf(" [%d] current=%d max=%d [%s]\n", i
,
1739 info
->mCurrentProgress
,
1740 info
->mMaxProgress
, buffer
.get());
1743 current
+= info
->mCurrentProgress
;
1745 if (info
->mMaxProgress
< info
->mCurrentProgress
) {
1748 max
+= info
->mMaxProgress
;
1753 printf("\nCurrent=%d Total=%d\n====\n", current
, max
);