123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nspr.h"
- #include "mozilla/BasicEvents.h"
- #include "mozilla/EventDispatcher.h"
- #include "mozilla/Logging.h"
- #include "nsDocLoader.h"
- #include "nsCURILoader.h"
- #include "nsNetUtil.h"
- #include "nsIHttpChannel.h"
- #include "nsIWebProgressListener2.h"
- #include "nsIServiceManager.h"
- #include "nsXPIDLString.h"
- #include "nsIURL.h"
- #include "nsCOMPtr.h"
- #include "nscore.h"
- #include "nsWeakPtr.h"
- #include "nsAutoPtr.h"
- #include "nsQueryObject.h"
- #include "nsIDOMWindow.h"
- #include "nsPIDOMWindow.h"
- #include "nsIStringBundle.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsITransport.h"
- #include "nsISocketTransport.h"
- #include "nsIDocShell.h"
- #include "nsIDOMDocument.h"
- #include "nsIDocument.h"
- #include "nsPresContext.h"
- #include "nsIAsyncVerifyRedirectCallback.h"
- using mozilla::DebugOnly;
- using mozilla::eLoad;
- using mozilla::EventDispatcher;
- using mozilla::LogLevel;
- using mozilla::WidgetEvent;
- static NS_DEFINE_CID(kThisImplCID, NS_THIS_DOCLOADER_IMPL_CID);
- //
- // Log module for nsIDocumentLoader logging...
- //
- // To enable logging (see mozilla/Logging.h for full details):
- //
- // set MOZ_LOG=DocLoader:5
- // set MOZ_LOG_FILE=debug.log
- //
- // this enables LogLevel::Debug level information and places all output in
- // the file 'debug.log'.
- //
- mozilla::LazyLogModule gDocLoaderLog("DocLoader");
- #if defined(DEBUG)
- void GetURIStringFromRequest(nsIRequest* request, nsACString &name)
- {
- if (request)
- request->GetName(name);
- else
- name.AssignLiteral("???");
- }
- #endif /* DEBUG */
- void
- nsDocLoader::RequestInfoHashInitEntry(PLDHashEntryHdr* entry,
- const void* key)
- {
- // Initialize the entry with placement new
- new (entry) nsRequestInfo(key);
- }
- void
- nsDocLoader::RequestInfoHashClearEntry(PLDHashTable* table,
- PLDHashEntryHdr* entry)
- {
- nsRequestInfo* info = static_cast<nsRequestInfo *>(entry);
- info->~nsRequestInfo();
- }
- // this is used for mListenerInfoList.Contains()
- template <>
- class nsDefaultComparator <nsDocLoader::nsListenerInfo, nsIWebProgressListener*> {
- public:
- bool Equals(const nsDocLoader::nsListenerInfo& aInfo,
- nsIWebProgressListener* const& aListener) const {
- nsCOMPtr<nsIWebProgressListener> listener =
- do_QueryReferent(aInfo.mWeakListener);
- return aListener == listener;
- }
- };
- /* static */ const PLDHashTableOps nsDocLoader::sRequestInfoHashOps =
- {
- PLDHashTable::HashVoidPtrKeyStub,
- PLDHashTable::MatchEntryStub,
- PLDHashTable::MoveEntryStub,
- nsDocLoader::RequestInfoHashClearEntry,
- nsDocLoader::RequestInfoHashInitEntry
- };
- nsDocLoader::nsDocLoader()
- : mParent(nullptr),
- mCurrentSelfProgress(0),
- mMaxSelfProgress(0),
- mCurrentTotalProgress(0),
- mMaxTotalProgress(0),
- mRequestInfoHash(&sRequestInfoHashOps, sizeof(nsRequestInfo)),
- mCompletedTotalProgress(0),
- mIsLoadingDocument(false),
- mIsRestoringDocument(false),
- mDontFlushLayout(false),
- mIsFlushingLayout(false),
- mDocumentOpenedButNotLoaded(false)
- {
- ClearInternalProgress();
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: created.\n", this));
- }
- nsresult
- nsDocLoader::SetDocLoaderParent(nsDocLoader *aParent)
- {
- mParent = aParent;
- return NS_OK;
- }
- nsresult
- nsDocLoader::Init()
- {
- nsresult rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), this);
- if (NS_FAILED(rv)) return rv;
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: load group %x.\n", this, mLoadGroup.get()));
- return NS_OK;
- }
- nsDocLoader::~nsDocLoader()
- {
- /*
- |ClearWeakReferences()| here is intended to prevent people holding weak references
- from re-entering this destructor since |QueryReferent()| will |AddRef()| me, and the
- subsequent |Release()| will try to destroy me. At this point there should be only
- weak references remaining (otherwise, we wouldn't be getting destroyed).
- An alternative would be incrementing our refcount (consider it a compressed flag
- saying "Don't re-destroy."). I haven't yet decided which is better. [scc]
- */
- // XXXbz now that NS_IMPL_RELEASE stabilizes by setting refcount to 1, is
- // this needed?
- ClearWeakReferences();
- Destroy();
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: deleted.\n", this));
- }
- /*
- * Implementation of ISupports methods...
- */
- NS_IMPL_ADDREF(nsDocLoader)
- NS_IMPL_RELEASE(nsDocLoader)
- NS_INTERFACE_MAP_BEGIN(nsDocLoader)
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequestObserver)
- NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
- NS_INTERFACE_MAP_ENTRY(nsIDocumentLoader)
- NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
- NS_INTERFACE_MAP_ENTRY(nsIWebProgress)
- NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
- NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
- NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
- NS_INTERFACE_MAP_ENTRY(nsISecurityEventSink)
- NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
- if (aIID.Equals(kThisImplCID))
- foundInterface = static_cast<nsIDocumentLoader *>(this);
- else
- NS_INTERFACE_MAP_END
- /*
- * Implementation of nsIInterfaceRequestor methods...
- */
- NS_IMETHODIMP nsDocLoader::GetInterface(const nsIID& aIID, void** aSink)
- {
- nsresult rv = NS_ERROR_NO_INTERFACE;
- NS_ENSURE_ARG_POINTER(aSink);
- if(aIID.Equals(NS_GET_IID(nsILoadGroup))) {
- *aSink = mLoadGroup;
- NS_IF_ADDREF((nsISupports*)*aSink);
- rv = NS_OK;
- } else {
- rv = QueryInterface(aIID, aSink);
- }
- return rv;
- }
- /* static */
- already_AddRefed<nsDocLoader>
- nsDocLoader::GetAsDocLoader(nsISupports* aSupports)
- {
- RefPtr<nsDocLoader> ret = do_QueryObject(aSupports);
- return ret.forget();
- }
- /* static */
- nsresult
- nsDocLoader::AddDocLoaderAsChildOfRoot(nsDocLoader* aDocLoader)
- {
- nsresult rv;
- nsCOMPtr<nsIDocumentLoader> docLoaderService =
- do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- RefPtr<nsDocLoader> rootDocLoader = GetAsDocLoader(docLoaderService);
- NS_ENSURE_TRUE(rootDocLoader, NS_ERROR_UNEXPECTED);
- return rootDocLoader->AddChildLoader(aDocLoader);
- }
- NS_IMETHODIMP
- nsDocLoader::Stop(void)
- {
- nsresult rv = NS_OK;
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: Stop() called\n", this));
- NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList, nsDocLoader, Stop, ());
- if (mLoadGroup)
- rv = mLoadGroup->Cancel(NS_BINDING_ABORTED);
- // Don't report that we're flushing layout so IsBusy returns false after a
- // Stop call.
- mIsFlushingLayout = false;
- // Clear out mChildrenInOnload. We want to make sure to fire our
- // onload at this point, and there's no issue with mChildrenInOnload
- // after this, since mDocumentRequest will be null after the
- // DocLoaderIsEmpty() call.
- mChildrenInOnload.Clear();
- // Make sure to call DocLoaderIsEmpty now so that we reset mDocumentRequest,
- // etc, as needed. We could be getting into here from a subframe onload, in
- // which case the call to DocLoaderIsEmpty() is coming but hasn't quite
- // happened yet, Canceling the loadgroup did nothing (because it was already
- // empty), and we're about to start a new load (which is what triggered this
- // Stop() call).
- // XXXbz If the child frame loadgroups were requests in mLoadgroup, I suspect
- // we wouldn't need the call here....
- NS_ASSERTION(!IsBusy(), "Shouldn't be busy here");
- DocLoaderIsEmpty(false);
- return rv;
- }
- bool
- nsDocLoader::IsBusy()
- {
- nsresult rv;
- //
- // A document loader is busy if either:
- //
- // 1. One of its children is in the middle of an onload handler. Note that
- // the handler may have already removed this child from mChildList!
- // 2. It is currently loading a document and either has parts of it still
- // loading, or has a busy child docloader.
- // 3. It's currently flushing layout in DocLoaderIsEmpty().
- //
- if (mChildrenInOnload.Count() || mIsFlushingLayout) {
- return true;
- }
- /* Is this document loader busy? */
- if (!IsBlockingLoadEvent()) {
- return false;
- }
- bool busy;
- rv = mLoadGroup->IsPending(&busy);
- if (NS_FAILED(rv)) {
- return false;
- }
- if (busy) {
- return true;
- }
- /* check its child document loaders... */
- uint32_t count = mChildList.Length();
- for (uint32_t i=0; i < count; i++) {
- nsIDocumentLoader* loader = ChildAt(i);
- // This is a safe cast, because we only put nsDocLoader objects into the
- // array
- if (loader && static_cast<nsDocLoader*>(loader)->IsBusy())
- return true;
- }
- return false;
- }
- NS_IMETHODIMP
- nsDocLoader::GetContainer(nsISupports** aResult)
- {
- NS_ADDREF(*aResult = static_cast<nsIDocumentLoader*>(this));
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocLoader::GetLoadGroup(nsILoadGroup** aResult)
- {
- nsresult rv = NS_OK;
- if (nullptr == aResult) {
- rv = NS_ERROR_NULL_POINTER;
- } else {
- *aResult = mLoadGroup;
- NS_IF_ADDREF(*aResult);
- }
- return rv;
- }
- void
- nsDocLoader::Destroy()
- {
- Stop();
- // Remove the document loader from the parent list of loaders...
- if (mParent)
- {
- DebugOnly<nsresult> rv = mParent->RemoveChildLoader(this);
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RemoveChildLoader failed");
- }
- // Release all the information about network requests...
- ClearRequestInfoHash();
- mListenerInfoList.Clear();
- mListenerInfoList.Compact();
- mDocumentRequest = nullptr;
- if (mLoadGroup)
- mLoadGroup->SetGroupObserver(nullptr);
- DestroyChildren();
- }
- void
- nsDocLoader::DestroyChildren()
- {
- uint32_t count = mChildList.Length();
- // if the doc loader still has children...we need to enumerate the
- // children and make them null out their back ptr to the parent doc
- // loader
- for (uint32_t i=0; i < count; i++)
- {
- nsIDocumentLoader* loader = ChildAt(i);
- if (loader) {
- // This is a safe cast, as we only put nsDocLoader objects into the
- // array
- DebugOnly<nsresult> rv =
- static_cast<nsDocLoader*>(loader)->SetDocLoaderParent(nullptr);
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetDocLoaderParent failed");
- }
- }
- mChildList.Clear();
- }
- NS_IMETHODIMP
- nsDocLoader::OnStartRequest(nsIRequest *request, nsISupports *aCtxt)
- {
- // called each time a request is added to the group.
- if (MOZ_LOG_TEST(gDocLoaderLog, LogLevel::Debug)) {
- nsAutoCString name;
- request->GetName(name);
- uint32_t count = 0;
- if (mLoadGroup)
- mLoadGroup->GetActiveCount(&count);
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: OnStartRequest[%p](%s) mIsLoadingDocument=%s, %u active URLs",
- this, request, name.get(),
- (mIsLoadingDocument ? "true" : "false"),
- count));
- }
- bool bJustStartedLoading = false;
- nsLoadFlags loadFlags = 0;
- request->GetLoadFlags(&loadFlags);
- if (!mIsLoadingDocument && (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)) {
- bJustStartedLoading = true;
- mIsLoadingDocument = true;
- mDocumentOpenedButNotLoaded = false;
- ClearInternalProgress(); // only clear our progress if we are starting a new load....
- }
- //
- // Create a new nsRequestInfo for the request that is starting to
- // load...
- //
- AddRequestInfo(request);
- //
- // Only fire a doStartDocumentLoad(...) if the document loader
- // has initiated a load... Otherwise, this notification has
- // resulted from a request being added to the load group.
- //
- if (mIsLoadingDocument) {
- if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
- //
- // Make sure that the document channel is null at this point...
- // (unless its been redirected)
- //
- NS_ASSERTION((loadFlags & nsIChannel::LOAD_REPLACE) ||
- !(mDocumentRequest.get()),
- "Overwriting an existing document channel!");
- // This request is associated with the entire document...
- mDocumentRequest = request;
- mLoadGroup->SetDefaultLoadRequest(request);
- // Only fire the start document load notification for the first
- // document URI... Do not fire it again for redirections
- //
- if (bJustStartedLoading) {
- // Update the progress status state
- mProgressStateFlags = nsIWebProgressListener::STATE_START;
- // Fire the start document load notification
- doStartDocumentLoad();
- return NS_OK;
- }
- }
- }
- NS_ASSERTION(!mIsLoadingDocument || mDocumentRequest,
- "mDocumentRequest MUST be set for the duration of a page load!");
- doStartURLLoad(request);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocLoader::OnStopRequest(nsIRequest *aRequest,
- nsISupports *aCtxt,
- nsresult aStatus)
- {
- nsresult rv = NS_OK;
- if (MOZ_LOG_TEST(gDocLoaderLog, LogLevel::Debug)) {
- nsAutoCString name;
- aRequest->GetName(name);
- uint32_t count = 0;
- if (mLoadGroup)
- mLoadGroup->GetActiveCount(&count);
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: OnStopRequest[%p](%s) status=%x"
- "mIsLoadingDocument=%s, mDocumentOpenedButNotLoaded=%s, %u active URLs",
- this, aRequest, name.get(),
- aStatus, (mIsLoadingDocument ? "true" : "false"),
- (mDocumentOpenedButNotLoaded ? "true" : "false"), count));
- }
- bool bFireTransferring = false;
- //
- // Set the Maximum progress to the same value as the current progress.
- // Since the URI has finished loading, all the data is there. Also,
- // this will allow a more accurate estimation of the max progress (in case
- // the old value was unknown ie. -1)
- //
- nsRequestInfo *info = GetRequestInfo(aRequest);
- if (info) {
- // Null out mLastStatus now so we don't find it when looking for
- // status from now on. This destroys the nsStatusInfo and hence
- // removes it from our list.
- info->mLastStatus = nullptr;
- int64_t oldMax = info->mMaxProgress;
- info->mMaxProgress = info->mCurrentProgress;
- //
- // If a request whose content-length was previously unknown has just
- // finished loading, then use this new data to try to calculate a
- // mMaxSelfProgress...
- //
- if ((oldMax < int64_t(0)) && (mMaxSelfProgress < int64_t(0))) {
- mMaxSelfProgress = CalculateMaxProgress();
- }
- // As we know the total progress of this request now, save it to be part
- // of CalculateMaxProgress() result. We need to remove the info from the
- // hash, see bug 480713.
- mCompletedTotalProgress += info->mMaxProgress;
- //
- // Determine whether a STATE_TRANSFERRING notification should be
- // 'synthesized'.
- //
- // If nsRequestInfo::mMaxProgress (as stored in oldMax) and
- // nsRequestInfo::mCurrentProgress are both 0, then the
- // STATE_TRANSFERRING notification has not been fired yet...
- //
- if ((oldMax == 0) && (info->mCurrentProgress == 0)) {
- nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
- // Only fire a TRANSFERRING notification if the request is also a
- // channel -- data transfer requires a nsIChannel!
- //
- if (channel) {
- if (NS_SUCCEEDED(aStatus)) {
- bFireTransferring = true;
- }
- //
- // If the request failed (for any reason other than being
- // redirected or retargeted), the TRANSFERRING notification can
- // still be fired if a HTTP connection was established to a server.
- //
- else if (aStatus != NS_BINDING_REDIRECTED &&
- aStatus != NS_BINDING_RETARGETED) {
- //
- // Only if the load has been targeted (see bug 268483)...
- //
- uint32_t lf;
- channel->GetLoadFlags(&lf);
- if (lf & nsIChannel::LOAD_TARGETED) {
- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
- if (httpChannel) {
- uint32_t responseCode;
- rv = httpChannel->GetResponseStatus(&responseCode);
- if (NS_SUCCEEDED(rv)) {
- //
- // A valid server status indicates that a connection was
- // established to the server... So, fire the notification
- // even though a failure occurred later...
- //
- bFireTransferring = true;
- }
- }
- }
- }
- }
- }
- }
- if (bFireTransferring) {
- // Send a STATE_TRANSFERRING notification for the request.
- int32_t flags;
- flags = nsIWebProgressListener::STATE_TRANSFERRING |
- nsIWebProgressListener::STATE_IS_REQUEST;
- //
- // Move the WebProgress into the STATE_TRANSFERRING state if necessary...
- //
- if (mProgressStateFlags & nsIWebProgressListener::STATE_START) {
- mProgressStateFlags = nsIWebProgressListener::STATE_TRANSFERRING;
- // Send STATE_TRANSFERRING for the document too...
- flags |= nsIWebProgressListener::STATE_IS_DOCUMENT;
- }
- FireOnStateChange(this, aRequest, flags, NS_OK);
- }
- //
- // Fire the OnStateChange(...) notification for stop request
- //
- doStopURLLoad(aRequest, aStatus);
- // Clear this request out of the hash to avoid bypass of FireOnStateChange
- // when address of the request is reused.
- RemoveRequestInfo(aRequest);
- //
- // Only fire the DocLoaderIsEmpty(...) if we may need to fire onload.
- //
- if (IsBlockingLoadEvent()) {
- nsCOMPtr<nsIDocShell> ds = do_QueryInterface(static_cast<nsIRequestObserver*>(this));
- bool doNotFlushLayout = false;
- if (ds) {
- // Don't do unexpected layout flushes while we're in process of restoring
- // a document from the bfcache.
- ds->GetRestoringDocument(&doNotFlushLayout);
- }
- DocLoaderIsEmpty(!doNotFlushLayout);
- }
- return NS_OK;
- }
- nsresult nsDocLoader::RemoveChildLoader(nsDocLoader* aChild)
- {
- nsresult rv = mChildList.RemoveElement(aChild) ? NS_OK : NS_ERROR_FAILURE;
- if (NS_SUCCEEDED(rv)) {
- rv = aChild->SetDocLoaderParent(nullptr);
- }
- return rv;
- }
- nsresult nsDocLoader::AddChildLoader(nsDocLoader* aChild)
- {
- nsresult rv = mChildList.AppendElement(aChild) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
- if (NS_SUCCEEDED(rv)) {
- rv = aChild->SetDocLoaderParent(this);
- }
- return rv;
- }
- NS_IMETHODIMP nsDocLoader::GetDocumentChannel(nsIChannel ** aChannel)
- {
- if (!mDocumentRequest) {
- *aChannel = nullptr;
- return NS_OK;
- }
- return CallQueryInterface(mDocumentRequest, aChannel);
- }
- void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout)
- {
- if (IsBlockingLoadEvent()) {
- /* In the unimagineably rude circumstance that onload event handlers
- triggered by this function actually kill the window ... ok, it's
- not unimagineable; it's happened ... this deathgrip keeps this object
- alive long enough to survive this function call. */
- nsCOMPtr<nsIDocumentLoader> kungFuDeathGrip(this);
- // Don't flush layout if we're still busy.
- if (IsBusy()) {
- return;
- }
- NS_ASSERTION(!mIsFlushingLayout, "Someone screwed up");
- // We may not have a document request if we are in a document.open() situation.
- NS_ASSERTION(mDocumentRequest || mDocumentOpenedButNotLoaded,
- "No Document Request!");
- // The load group for this DocumentLoader is idle. Flush if we need to.
- if (aFlushLayout && !mDontFlushLayout) {
- nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(GetAsSupports(this));
- nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
- if (doc) {
- // We start loads from style resolution, so we need to flush out style
- // no matter what. If we have user fonts, we also need to flush layout,
- // since the reflow is what starts font loads.
- mozFlushType flushType = Flush_Style;
- nsIPresShell* shell = doc->GetShell();
- if (shell) {
- // Be safe in case this presshell is in teardown now
- nsPresContext* presContext = shell->GetPresContext();
- if (presContext && presContext->GetUserFontSet()) {
- flushType = Flush_Layout;
- }
- }
- mDontFlushLayout = mIsFlushingLayout = true;
- doc->FlushPendingNotifications(flushType);
- mDontFlushLayout = mIsFlushingLayout = false;
- }
- }
- // And now check whether we're really busy; that might have changed with
- // the layout flush.
- //
- // Note, mDocumentRequest can be null while mDocumentOpenedButNotLoaded is
- // false if the flushing above re-entered this method. Exit in that case.
- if (IsBusy() || (!mDocumentRequest && !mDocumentOpenedButNotLoaded)) {
- return;
- }
- if (mDocumentRequest) {
- // Clear out our request info hash, now that our load really is done and
- // we don't need it anymore to CalculateMaxProgress().
- ClearInternalProgress();
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: Is now idle...\n", this));
- nsCOMPtr<nsIRequest> docRequest = mDocumentRequest;
- mDocumentRequest = nullptr;
- mIsLoadingDocument = false;
- // Update the progress status state - the document is done
- mProgressStateFlags = nsIWebProgressListener::STATE_STOP;
- nsresult loadGroupStatus = NS_OK;
- mLoadGroup->GetStatus(&loadGroupStatus);
- //
- // New code to break the circular reference between
- // the load group and the docloader...
- //
- mLoadGroup->SetDefaultLoadRequest(nullptr);
- // Take a ref to our parent now so that we can call ChildDoneWithOnload() on
- // it even if our onload handler removes us from the docloader tree.
- RefPtr<nsDocLoader> parent = mParent;
- // Note that if calling ChildEnteringOnload() on the parent returns false
- // then calling our onload handler is not safe. That can only happen on
- // OOM, so that's ok.
- if (!parent || parent->ChildEnteringOnload(this)) {
- // Do nothing with our state after firing the
- // OnEndDocumentLoad(...). The document loader may be loading a *new*
- // document - if LoadDocument() was called from a handler!
- //
- doStopDocumentLoad(docRequest, loadGroupStatus);
- if (parent) {
- parent->ChildDoneWithOnload(this);
- }
- }
- } else {
- MOZ_ASSERT(mDocumentOpenedButNotLoaded);
- mDocumentOpenedButNotLoaded = false;
- // Make sure we do the ChildEnteringOnload/ChildDoneWithOnload even if we
- // plan to skip firing our own load event, because otherwise we might
- // never end up firing our parent's load event.
- RefPtr<nsDocLoader> parent = mParent;
- if (!parent || parent->ChildEnteringOnload(this)) {
- nsresult loadGroupStatus = NS_OK;
- mLoadGroup->GetStatus(&loadGroupStatus);
- // Make sure we're not canceling the loadgroup. If we are, then we should
- // not fire a load event just like in the normal navigation case.
- if (NS_SUCCEEDED(loadGroupStatus) ||
- loadGroupStatus == NS_ERROR_PARSED_DATA_CACHED) {
- // Can "doc" or "window" ever come back null here? Our state machine
- // is complicated enough, so I wouldn't bet against it...
- nsCOMPtr<nsIDocument> doc = do_GetInterface(GetAsSupports(this));
- if (doc) {
- doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE,
- /* updateTimingInformation = */ false);
- nsCOMPtr<nsPIDOMWindowOuter> window = doc->GetWindow();
- if (window && !doc->SkipLoadEventAfterClose()) {
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: Firing load event for document.open\n",
- this));
- // This is a very cut-down version of
- // nsDocumentViewer::LoadComplete that doesn't do various things
- // that are not relevant here because this wasn't an actual
- // navigation.
- WidgetEvent event(true, eLoad);
- event.mFlags.mBubbles = false;
- event.mFlags.mCancelable = false;
- // Dispatching to |window|, but using |document| as the target,
- // per spec.
- event.mTarget = doc;
- nsEventStatus unused = nsEventStatus_eIgnore;
- doc->SetLoadEventFiring(true);
- EventDispatcher::Dispatch(window, nullptr, &event, nullptr,
- &unused);
- doc->SetLoadEventFiring(false);
- // Now unsuppress painting on the presshell, if we
- // haven't done that yet.
- nsCOMPtr<nsIPresShell> shell = doc->GetShell();
- if (shell && !shell->IsDestroying()) {
- shell->UnsuppressPainting();
- if (!shell->IsDestroying()) {
- shell->LoadComplete();
- }
- }
- }
- }
- }
- if (parent) {
- parent->ChildDoneWithOnload(this);
- }
- }
- }
- }
- }
- void nsDocLoader::doStartDocumentLoad(void)
- {
- #if defined(DEBUG)
- nsAutoCString buffer;
- GetURIStringFromRequest(mDocumentRequest, buffer);
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: ++ Firing OnStateChange for start document load (...)."
- "\tURI: %s \n",
- this, buffer.get()));
- #endif /* DEBUG */
- // Fire an OnStatus(...) notification STATE_START. This indicates
- // that the document represented by mDocumentRequest has started to
- // load...
- FireOnStateChange(this,
- mDocumentRequest,
- nsIWebProgressListener::STATE_START |
- nsIWebProgressListener::STATE_IS_DOCUMENT |
- nsIWebProgressListener::STATE_IS_REQUEST |
- nsIWebProgressListener::STATE_IS_WINDOW |
- nsIWebProgressListener::STATE_IS_NETWORK,
- NS_OK);
- }
- void nsDocLoader::doStartURLLoad(nsIRequest *request)
- {
- #if defined(DEBUG)
- nsAutoCString buffer;
- GetURIStringFromRequest(request, buffer);
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: ++ Firing OnStateChange start url load (...)."
- "\tURI: %s\n",
- this, buffer.get()));
- #endif /* DEBUG */
- FireOnStateChange(this,
- request,
- nsIWebProgressListener::STATE_START |
- nsIWebProgressListener::STATE_IS_REQUEST,
- NS_OK);
- }
- void nsDocLoader::doStopURLLoad(nsIRequest *request, nsresult aStatus)
- {
- #if defined(DEBUG)
- nsAutoCString buffer;
- GetURIStringFromRequest(request, buffer);
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: ++ Firing OnStateChange for end url load (...)."
- "\tURI: %s status=%x\n",
- this, buffer.get(), aStatus));
- #endif /* DEBUG */
- FireOnStateChange(this,
- request,
- nsIWebProgressListener::STATE_STOP |
- nsIWebProgressListener::STATE_IS_REQUEST,
- aStatus);
- // Fire a status change message for the most recent unfinished
- // request to make sure that the displayed status is not outdated.
- if (!mStatusInfoList.isEmpty()) {
- nsStatusInfo* statusInfo = mStatusInfoList.getFirst();
- FireOnStatusChange(this, statusInfo->mRequest,
- statusInfo->mStatusCode,
- statusInfo->mStatusMessage.get());
- }
- }
- void nsDocLoader::doStopDocumentLoad(nsIRequest *request,
- nsresult aStatus)
- {
- #if defined(DEBUG)
- nsAutoCString buffer;
- GetURIStringFromRequest(request, buffer);
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: ++ Firing OnStateChange for end document load (...)."
- "\tURI: %s Status=%x\n",
- this, buffer.get(), aStatus));
- #endif /* DEBUG */
- // Firing STATE_STOP|STATE_IS_DOCUMENT will fire onload handlers.
- // Grab our parent chain before doing that so we can still dispatch
- // STATE_STOP|STATE_IS_WINDW_STATE_IS_NETWORK to them all, even if
- // the onload handlers rearrange the docshell tree.
- WebProgressList list;
- GatherAncestorWebProgresses(list);
- //
- // Fire an OnStateChange(...) notification indicating the the
- // current document has finished loading...
- //
- int32_t flags = nsIWebProgressListener::STATE_STOP |
- nsIWebProgressListener::STATE_IS_DOCUMENT;
- for (uint32_t i = 0; i < list.Length(); ++i) {
- list[i]->DoFireOnStateChange(this, request, flags, aStatus);
- }
- //
- // Fire a final OnStateChange(...) notification indicating the the
- // current document has finished loading...
- //
- flags = nsIWebProgressListener::STATE_STOP |
- nsIWebProgressListener::STATE_IS_WINDOW |
- nsIWebProgressListener::STATE_IS_NETWORK;
- for (uint32_t i = 0; i < list.Length(); ++i) {
- list[i]->DoFireOnStateChange(this, request, flags, aStatus);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // The following section contains support for nsIWebProgress and related stuff
- ////////////////////////////////////////////////////////////////////////////////////
- NS_IMETHODIMP
- nsDocLoader::AddProgressListener(nsIWebProgressListener *aListener,
- uint32_t aNotifyMask)
- {
- if (mListenerInfoList.Contains(aListener)) {
- // The listener is already registered!
- return NS_ERROR_FAILURE;
- }
- nsWeakPtr listener = do_GetWeakReference(aListener);
- if (!listener) {
- return NS_ERROR_INVALID_ARG;
- }
- return mListenerInfoList.AppendElement(nsListenerInfo(listener, aNotifyMask)) ?
- NS_OK : NS_ERROR_OUT_OF_MEMORY;
- }
- NS_IMETHODIMP
- nsDocLoader::RemoveProgressListener(nsIWebProgressListener *aListener)
- {
- return mListenerInfoList.RemoveElement(aListener) ? NS_OK : NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsDocLoader::GetDOMWindow(mozIDOMWindowProxy **aResult)
- {
- return CallGetInterface(this, aResult);
- }
- NS_IMETHODIMP
- nsDocLoader::GetDOMWindowID(uint64_t *aResult)
- {
- *aResult = 0;
- nsCOMPtr<mozIDOMWindowProxy> window;
- nsresult rv = GetDOMWindow(getter_AddRefs(window));
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsPIDOMWindowOuter> piwindow = nsPIDOMWindowOuter::From(window);
- NS_ENSURE_STATE(piwindow);
- MOZ_ASSERT(piwindow->IsOuterWindow());
- *aResult = piwindow->WindowID();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocLoader::GetIsTopLevel(bool *aResult)
- {
- *aResult = false;
- nsCOMPtr<mozIDOMWindowProxy> window;
- GetDOMWindow(getter_AddRefs(window));
- if (window) {
- nsCOMPtr<nsPIDOMWindowOuter> piwindow = nsPIDOMWindowOuter::From(window);
- NS_ENSURE_STATE(piwindow);
- nsCOMPtr<nsPIDOMWindowOuter> topWindow = piwindow->GetTop();
- *aResult = piwindow == topWindow;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocLoader::GetIsLoadingDocument(bool *aIsLoadingDocument)
- {
- *aIsLoadingDocument = mIsLoadingDocument;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocLoader::GetLoadType(uint32_t *aLoadType)
- {
- *aLoadType = 0;
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- int64_t nsDocLoader::GetMaxTotalProgress()
- {
- int64_t newMaxTotal = 0;
- uint32_t count = mChildList.Length();
- for (uint32_t i=0; i < count; i++)
- {
- int64_t individualProgress = 0;
- nsIDocumentLoader* docloader = ChildAt(i);
- if (docloader)
- {
- // Cast is safe since all children are nsDocLoader too
- individualProgress = ((nsDocLoader *) docloader)->GetMaxTotalProgress();
- }
- if (individualProgress < int64_t(0)) // if one of the elements doesn't know it's size
- // then none of them do
- {
- newMaxTotal = int64_t(-1);
- break;
- }
- else
- newMaxTotal += individualProgress;
- }
- int64_t progress = -1;
- if (mMaxSelfProgress >= int64_t(0) && newMaxTotal >= int64_t(0))
- progress = newMaxTotal + mMaxSelfProgress;
- return progress;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // The following section contains support for nsIProgressEventSink which is used to
- // pass progress and status between the actual request and the doc loader. The doc loader
- // then turns around and makes the right web progress calls based on this information.
- ////////////////////////////////////////////////////////////////////////////////////
- NS_IMETHODIMP nsDocLoader::OnProgress(nsIRequest *aRequest, nsISupports* ctxt,
- int64_t aProgress, int64_t aProgressMax)
- {
- int64_t progressDelta = 0;
- //
- // Update the RequestInfo entry with the new progress data
- //
- if (nsRequestInfo* info = GetRequestInfo(aRequest)) {
- // Update info->mCurrentProgress before we call FireOnStateChange,
- // since that can make the "info" pointer invalid.
- int64_t oldCurrentProgress = info->mCurrentProgress;
- progressDelta = aProgress - oldCurrentProgress;
- info->mCurrentProgress = aProgress;
- // suppress sending STATE_TRANSFERRING if this is upload progress (see bug 240053)
- if (!info->mUploading && (int64_t(0) == oldCurrentProgress) && (int64_t(0) == info->mMaxProgress)) {
- //
- // If we receive an OnProgress event from a toplevel channel that the URI Loader
- // has not yet targeted, then we must suppress the event. This is necessary to
- // ensure that webprogresslisteners do not get confused when the channel is
- // finally targeted. See bug 257308.
- //
- nsLoadFlags lf = 0;
- aRequest->GetLoadFlags(&lf);
- if ((lf & nsIChannel::LOAD_DOCUMENT_URI) && !(lf & nsIChannel::LOAD_TARGETED)) {
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p Ignoring OnProgress while load is not targeted\n", this));
- return NS_OK;
- }
- //
- // This is the first progress notification for the entry. If
- // (aMaxProgress != -1) then the content-length of the data is known,
- // so update mMaxSelfProgress... Otherwise, set it to -1 to indicate
- // that the content-length is no longer known.
- //
- if (aProgressMax != -1) {
- mMaxSelfProgress += aProgressMax;
- info->mMaxProgress = aProgressMax;
- } else {
- mMaxSelfProgress = int64_t(-1);
- info->mMaxProgress = int64_t(-1);
- }
- // Send a STATE_TRANSFERRING notification for the request.
- int32_t flags;
- flags = nsIWebProgressListener::STATE_TRANSFERRING |
- nsIWebProgressListener::STATE_IS_REQUEST;
- //
- // Move the WebProgress into the STATE_TRANSFERRING state if necessary...
- //
- if (mProgressStateFlags & nsIWebProgressListener::STATE_START) {
- mProgressStateFlags = nsIWebProgressListener::STATE_TRANSFERRING;
- // Send STATE_TRANSFERRING for the document too...
- flags |= nsIWebProgressListener::STATE_IS_DOCUMENT;
- }
- FireOnStateChange(this, aRequest, flags, NS_OK);
- }
- // Update our overall current progress count.
- mCurrentSelfProgress += progressDelta;
- }
- //
- // The request is not part of the load group, so ignore its progress
- // information...
- //
- else {
- #if defined(DEBUG)
- nsAutoCString buffer;
- GetURIStringFromRequest(aRequest, buffer);
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p OOPS - No Request Info for: %s\n",
- this, buffer.get()));
- #endif /* DEBUG */
- return NS_OK;
- }
- //
- // Fire progress notifications out to any registered nsIWebProgressListeners
- //
- FireOnProgressChange(this, aRequest, aProgress, aProgressMax, progressDelta,
- mCurrentTotalProgress, mMaxTotalProgress);
- return NS_OK;
- }
- NS_IMETHODIMP nsDocLoader::OnStatus(nsIRequest* aRequest, nsISupports* ctxt,
- nsresult aStatus, const char16_t* aStatusArg)
- {
- //
- // Fire progress notifications out to any registered nsIWebProgressListeners
- //
- if (aStatus != NS_OK) {
- // Remember the current status for this request
- nsRequestInfo *info;
- info = GetRequestInfo(aRequest);
- if (info) {
- bool uploading = (aStatus == NS_NET_STATUS_WRITING ||
- aStatus == NS_NET_STATUS_SENDING_TO);
- // If switching from uploading to downloading (or vice versa), then we
- // need to reset our progress counts. This is designed with HTTP form
- // submission in mind, where an upload is performed followed by download
- // of possibly several documents.
- if (info->mUploading != uploading) {
- mCurrentSelfProgress = mMaxSelfProgress = 0;
- mCurrentTotalProgress = mMaxTotalProgress = 0;
- mCompletedTotalProgress = 0;
- info->mUploading = uploading;
- info->mCurrentProgress = 0;
- info->mMaxProgress = 0;
- }
- }
- nsCOMPtr<nsIStringBundleService> sbs =
- mozilla::services::GetStringBundleService();
- if (!sbs)
- return NS_ERROR_FAILURE;
- nsXPIDLString msg;
- nsresult rv = sbs->FormatStatusMessage(aStatus, aStatusArg,
- getter_Copies(msg));
- if (NS_FAILED(rv))
- return rv;
- // Keep around the message. In case a request finishes, we need to make sure
- // to send the status message of another request to our user to that we
- // don't display, for example, "Transferring" messages for requests that are
- // already done.
- if (info) {
- if (!info->mLastStatus) {
- info->mLastStatus = new nsStatusInfo(aRequest);
- } else {
- // We're going to move it to the front of the list, so remove
- // it from wherever it is now.
- info->mLastStatus->remove();
- }
- info->mLastStatus->mStatusMessage = msg;
- info->mLastStatus->mStatusCode = aStatus;
- // Put the info at the front of the list
- mStatusInfoList.insertFront(info->mLastStatus);
- }
- FireOnStatusChange(this, aRequest, aStatus, msg);
- }
- return NS_OK;
- }
- void nsDocLoader::ClearInternalProgress()
- {
- ClearRequestInfoHash();
- mCurrentSelfProgress = mMaxSelfProgress = 0;
- mCurrentTotalProgress = mMaxTotalProgress = 0;
- mCompletedTotalProgress = 0;
- mProgressStateFlags = nsIWebProgressListener::STATE_STOP;
- }
- /**
- * |_code| is executed for every listener matching |_flag|
- * |listener| should be used inside |_code| as the nsIWebProgressListener var.
- */
- #define NOTIFY_LISTENERS(_flag, _code) \
- PR_BEGIN_MACRO \
- nsCOMPtr<nsIWebProgressListener> listener; \
- ListenerArray::BackwardIterator iter(mListenerInfoList); \
- while (iter.HasMore()) { \
- nsListenerInfo &info = iter.GetNext(); \
- if (!(info.mNotifyMask & (_flag))) { \
- continue; \
- } \
- listener = do_QueryReferent(info.mWeakListener); \
- if (!listener) { \
- iter.Remove(); \
- continue; \
- } \
- _code \
- } \
- mListenerInfoList.Compact(); \
- PR_END_MACRO
- void nsDocLoader::FireOnProgressChange(nsDocLoader *aLoadInitiator,
- nsIRequest *request,
- int64_t aProgress,
- int64_t aProgressMax,
- int64_t aProgressDelta,
- int64_t aTotalProgress,
- int64_t aMaxTotalProgress)
- {
- if (mIsLoadingDocument) {
- mCurrentTotalProgress += aProgressDelta;
- mMaxTotalProgress = GetMaxTotalProgress();
- aTotalProgress = mCurrentTotalProgress;
- aMaxTotalProgress = mMaxTotalProgress;
- }
- #if defined(DEBUG)
- nsAutoCString buffer;
- GetURIStringFromRequest(request, buffer);
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: Progress (%s): curSelf: %d maxSelf: %d curTotal: %d maxTotal %d\n",
- this, buffer.get(), aProgress, aProgressMax, aTotalProgress, aMaxTotalProgress));
- #endif /* DEBUG */
- NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_PROGRESS,
- // XXX truncates 64-bit to 32-bit
- listener->OnProgressChange(aLoadInitiator,request,
- int32_t(aProgress), int32_t(aProgressMax),
- int32_t(aTotalProgress), int32_t(aMaxTotalProgress));
- );
- // Pass the notification up to the parent...
- if (mParent) {
- mParent->FireOnProgressChange(aLoadInitiator, request,
- aProgress, aProgressMax,
- aProgressDelta,
- aTotalProgress, aMaxTotalProgress);
- }
- }
- void nsDocLoader::GatherAncestorWebProgresses(WebProgressList& aList)
- {
- for (nsDocLoader* loader = this; loader; loader = loader->mParent) {
- aList.AppendElement(loader);
- }
- }
- void nsDocLoader::FireOnStateChange(nsIWebProgress *aProgress,
- nsIRequest *aRequest,
- int32_t aStateFlags,
- nsresult aStatus)
- {
- WebProgressList list;
- GatherAncestorWebProgresses(list);
- for (uint32_t i = 0; i < list.Length(); ++i) {
- list[i]->DoFireOnStateChange(aProgress, aRequest, aStateFlags, aStatus);
- }
- }
- void nsDocLoader::DoFireOnStateChange(nsIWebProgress * const aProgress,
- nsIRequest * const aRequest,
- int32_t &aStateFlags,
- const nsresult aStatus)
- {
- //
- // Remove the STATE_IS_NETWORK bit if necessary.
- //
- // The rule is to remove this bit, if the notification has been passed
- // up from a child WebProgress, and the current WebProgress is already
- // active...
- //
- if (mIsLoadingDocument &&
- (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) &&
- (this != aProgress)) {
- aStateFlags &= ~nsIWebProgressListener::STATE_IS_NETWORK;
- }
- // Add the STATE_RESTORING bit if necessary.
- if (mIsRestoringDocument)
- aStateFlags |= nsIWebProgressListener::STATE_RESTORING;
- #if defined(DEBUG)
- nsAutoCString buffer;
- GetURIStringFromRequest(aRequest, buffer);
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: Status (%s): code: %x\n",
- this, buffer.get(), aStateFlags));
- #endif /* DEBUG */
- NS_ASSERTION(aRequest, "Firing OnStateChange(...) notification with a NULL request!");
- NOTIFY_LISTENERS(((aStateFlags >> 16) & nsIWebProgress::NOTIFY_STATE_ALL),
- listener->OnStateChange(aProgress, aRequest, aStateFlags, aStatus);
- );
- }
- void
- nsDocLoader::FireOnLocationChange(nsIWebProgress* aWebProgress,
- nsIRequest* aRequest,
- nsIURI *aUri,
- uint32_t aFlags)
- {
- NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_LOCATION,
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug, ("DocLoader [%p] calling %p->OnLocationChange", this, listener.get()));
- listener->OnLocationChange(aWebProgress, aRequest, aUri, aFlags);
- );
- // Pass the notification up to the parent...
- if (mParent) {
- mParent->FireOnLocationChange(aWebProgress, aRequest, aUri, aFlags);
- }
- }
- void
- nsDocLoader::FireOnStatusChange(nsIWebProgress* aWebProgress,
- nsIRequest* aRequest,
- nsresult aStatus,
- const char16_t* aMessage)
- {
- NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_STATUS,
- listener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
- );
- // Pass the notification up to the parent...
- if (mParent) {
- mParent->FireOnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
- }
- }
- bool
- nsDocLoader::RefreshAttempted(nsIWebProgress* aWebProgress,
- nsIURI *aURI,
- int32_t aDelay,
- bool aSameURI)
- {
- /*
- * Returns true if the refresh may proceed,
- * false if the refresh should be blocked.
- */
- bool allowRefresh = true;
- NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_REFRESH,
- nsCOMPtr<nsIWebProgressListener2> listener2 =
- do_QueryReferent(info.mWeakListener);
- if (!listener2)
- continue;
- bool listenerAllowedRefresh;
- nsresult listenerRV = listener2->OnRefreshAttempted(
- aWebProgress, aURI, aDelay, aSameURI, &listenerAllowedRefresh);
- if (NS_FAILED(listenerRV))
- continue;
- allowRefresh = allowRefresh && listenerAllowedRefresh;
- );
- // Pass the notification up to the parent...
- if (mParent) {
- allowRefresh = allowRefresh &&
- mParent->RefreshAttempted(aWebProgress, aURI, aDelay, aSameURI);
- }
- return allowRefresh;
- }
- nsresult nsDocLoader::AddRequestInfo(nsIRequest *aRequest)
- {
- if (!mRequestInfoHash.Add(aRequest, mozilla::fallible)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- return NS_OK;
- }
- void nsDocLoader::RemoveRequestInfo(nsIRequest *aRequest)
- {
- mRequestInfoHash.Remove(aRequest);
- }
- nsDocLoader::nsRequestInfo* nsDocLoader::GetRequestInfo(nsIRequest* aRequest)
- {
- return static_cast<nsRequestInfo*>(mRequestInfoHash.Search(aRequest));
- }
- void nsDocLoader::ClearRequestInfoHash(void)
- {
- mRequestInfoHash.Clear();
- }
- int64_t nsDocLoader::CalculateMaxProgress()
- {
- int64_t max = mCompletedTotalProgress;
- for (auto iter = mRequestInfoHash.Iter(); !iter.Done(); iter.Next()) {
- auto info = static_cast<const nsRequestInfo*>(iter.Get());
- if (info->mMaxProgress < info->mCurrentProgress) {
- return int64_t(-1);
- }
- max += info->mMaxProgress;
- }
- return max;
- }
- NS_IMETHODIMP nsDocLoader::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
- nsIChannel *aNewChannel,
- uint32_t aFlags,
- nsIAsyncVerifyRedirectCallback *cb)
- {
- if (aOldChannel)
- {
- nsLoadFlags loadFlags = 0;
- int32_t stateFlags = nsIWebProgressListener::STATE_REDIRECTING |
- nsIWebProgressListener::STATE_IS_REQUEST;
- aOldChannel->GetLoadFlags(&loadFlags);
- // If the document channel is being redirected, then indicate that the
- // document is being redirected in the notification...
- if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
- {
- stateFlags |= nsIWebProgressListener::STATE_IS_DOCUMENT;
- #if defined(DEBUG)
- nsCOMPtr<nsIRequest> request(do_QueryInterface(aOldChannel));
- NS_ASSERTION(request == mDocumentRequest, "Wrong Document Channel");
- #endif /* DEBUG */
- }
- OnRedirectStateChange(aOldChannel, aNewChannel, aFlags, stateFlags);
- FireOnStateChange(this, aOldChannel, stateFlags, NS_OK);
- }
- cb->OnRedirectVerifyCallback(NS_OK);
- return NS_OK;
- }
- /*
- * Implementation of nsISecurityEventSink method...
- */
- NS_IMETHODIMP nsDocLoader::OnSecurityChange(nsISupports * aContext,
- uint32_t aState)
- {
- //
- // Fire progress notifications out to any registered nsIWebProgressListeners.
- //
- nsCOMPtr<nsIRequest> request = do_QueryInterface(aContext);
- nsIWebProgress* webProgress = static_cast<nsIWebProgress*>(this);
- NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_SECURITY,
- listener->OnSecurityChange(webProgress, request, aState);
- );
- // Pass the notification up to the parent...
- if (mParent) {
- mParent->OnSecurityChange(aContext, aState);
- }
- return NS_OK;
- }
- /*
- * Implementation of nsISupportsPriority methods...
- *
- * The priority of the DocLoader _is_ the priority of its LoadGroup.
- *
- * XXX(darin): Once we start storing loadgroups in loadgroups, this code will
- * go away.
- */
- NS_IMETHODIMP nsDocLoader::GetPriority(int32_t *aPriority)
- {
- nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup);
- if (p)
- return p->GetPriority(aPriority);
- *aPriority = 0;
- return NS_OK;
- }
- NS_IMETHODIMP nsDocLoader::SetPriority(int32_t aPriority)
- {
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: SetPriority(%d) called\n", this, aPriority));
- nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup);
- if (p)
- p->SetPriority(aPriority);
- NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList, nsDocLoader,
- SetPriority, (aPriority));
- return NS_OK;
- }
- NS_IMETHODIMP nsDocLoader::AdjustPriority(int32_t aDelta)
- {
- MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
- ("DocLoader:%p: AdjustPriority(%d) called\n", this, aDelta));
- nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup);
- if (p)
- p->AdjustPriority(aDelta);
- NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList, nsDocLoader,
- AdjustPriority, (aDelta));
- return NS_OK;
- }
- #if 0
- void nsDocLoader::DumpChannelInfo()
- {
- nsChannelInfo *info;
- int32_t i, count;
- int32_t current=0, max=0;
- printf("==== DocLoader=%x\n", this);
- count = mChannelInfoList.Count();
- for(i=0; i<count; i++) {
- info = (nsChannelInfo *)mChannelInfoList.ElementAt(i);
- #if defined(DEBUG)
- nsAutoCString buffer;
- nsresult rv = NS_OK;
- if (info->mURI) {
- rv = info->mURI->GetSpec(buffer);
- }
- printf(" [%d] current=%d max=%d [%s]\n", i,
- info->mCurrentProgress,
- info->mMaxProgress, buffer.get());
- #endif /* DEBUG */
- current += info->mCurrentProgress;
- if (max >= 0) {
- if (info->mMaxProgress < info->mCurrentProgress) {
- max = -1;
- } else {
- max += info->mMaxProgress;
- }
- }
- }
- printf("\nCurrent=%d Total=%d\n====\n", current, max);
- }
- #endif /* 0 */
|