1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/uriloader/base/nsDocLoader.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1754 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nspr.h" 1.10 +#include "prlog.h" 1.11 + 1.12 +#include "nsDocLoader.h" 1.13 +#include "nsCURILoader.h" 1.14 +#include "nsNetUtil.h" 1.15 +#include "nsIHttpChannel.h" 1.16 +#include "nsIWebProgressListener2.h" 1.17 + 1.18 +#include "nsIServiceManager.h" 1.19 +#include "nsXPIDLString.h" 1.20 + 1.21 +#include "nsIURL.h" 1.22 +#include "nsCOMPtr.h" 1.23 +#include "nscore.h" 1.24 +#include "nsWeakPtr.h" 1.25 +#include "nsAutoPtr.h" 1.26 + 1.27 +#include "nsIDOMWindow.h" 1.28 + 1.29 +#include "nsIStringBundle.h" 1.30 +#include "nsIScriptSecurityManager.h" 1.31 + 1.32 +#include "nsITransport.h" 1.33 +#include "nsISocketTransport.h" 1.34 + 1.35 +#include "nsIDOMDocument.h" 1.36 +#include "nsIDocument.h" 1.37 +#include "nsPresContext.h" 1.38 +#include "nsIAsyncVerifyRedirectCallback.h" 1.39 + 1.40 +static NS_DEFINE_CID(kThisImplCID, NS_THIS_DOCLOADER_IMPL_CID); 1.41 + 1.42 +#if defined(PR_LOGGING) 1.43 +// 1.44 +// Log module for nsIDocumentLoader logging... 1.45 +// 1.46 +// To enable logging (see prlog.h for full details): 1.47 +// 1.48 +// set NSPR_LOG_MODULES=DocLoader:5 1.49 +// set NSPR_LOG_FILE=nspr.log 1.50 +// 1.51 +// this enables PR_LOG_DEBUG level information and places all output in 1.52 +// the file nspr.log 1.53 +// 1.54 +PRLogModuleInfo* gDocLoaderLog = nullptr; 1.55 +#endif /* PR_LOGGING */ 1.56 + 1.57 + 1.58 +#if defined(DEBUG) 1.59 +void GetURIStringFromRequest(nsIRequest* request, nsACString &name) 1.60 +{ 1.61 + if (request) 1.62 + request->GetName(name); 1.63 + else 1.64 + name.AssignLiteral("???"); 1.65 +} 1.66 +#endif /* DEBUG */ 1.67 + 1.68 + 1.69 + 1.70 +bool 1.71 +nsDocLoader::RequestInfoHashInitEntry(PLDHashTable* table, 1.72 + PLDHashEntryHdr* entry, 1.73 + const void* key) 1.74 +{ 1.75 + // Initialize the entry with placement new 1.76 + new (entry) nsRequestInfo(key); 1.77 + return true; 1.78 +} 1.79 + 1.80 +void 1.81 +nsDocLoader::RequestInfoHashClearEntry(PLDHashTable* table, 1.82 + PLDHashEntryHdr* entry) 1.83 +{ 1.84 + nsRequestInfo* info = static_cast<nsRequestInfo *>(entry); 1.85 + info->~nsRequestInfo(); 1.86 +} 1.87 + 1.88 +struct nsListenerInfo { 1.89 + nsListenerInfo(nsIWeakReference *aListener, unsigned long aNotifyMask) 1.90 + : mWeakListener(aListener), 1.91 + mNotifyMask(aNotifyMask) 1.92 + { 1.93 + } 1.94 + 1.95 + // Weak pointer for the nsIWebProgressListener... 1.96 + nsWeakPtr mWeakListener; 1.97 + 1.98 + // Mask indicating which notifications the listener wants to receive. 1.99 + unsigned long mNotifyMask; 1.100 +}; 1.101 + 1.102 + 1.103 +nsDocLoader::nsDocLoader() 1.104 + : mParent(nullptr), 1.105 + mListenerInfoList(8), 1.106 + mCurrentSelfProgress(0), 1.107 + mMaxSelfProgress(0), 1.108 + mCurrentTotalProgress(0), 1.109 + mMaxTotalProgress(0), 1.110 + mCompletedTotalProgress(0), 1.111 + mIsLoadingDocument(false), 1.112 + mIsRestoringDocument(false), 1.113 + mDontFlushLayout(false), 1.114 + mIsFlushingLayout(false) 1.115 +{ 1.116 +#if defined(PR_LOGGING) 1.117 + if (nullptr == gDocLoaderLog) { 1.118 + gDocLoaderLog = PR_NewLogModule("DocLoader"); 1.119 + } 1.120 +#endif /* PR_LOGGING */ 1.121 + 1.122 + static const PLDHashTableOps hash_table_ops = 1.123 + { 1.124 + PL_DHashAllocTable, 1.125 + PL_DHashFreeTable, 1.126 + PL_DHashVoidPtrKeyStub, 1.127 + PL_DHashMatchEntryStub, 1.128 + PL_DHashMoveEntryStub, 1.129 + RequestInfoHashClearEntry, 1.130 + PL_DHashFinalizeStub, 1.131 + RequestInfoHashInitEntry 1.132 + }; 1.133 + 1.134 + PL_DHashTableInit(&mRequestInfoHash, &hash_table_ops, nullptr, 1.135 + sizeof(nsRequestInfo), 16); 1.136 + 1.137 + ClearInternalProgress(); 1.138 + 1.139 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.140 + ("DocLoader:%p: created.\n", this)); 1.141 +} 1.142 + 1.143 +nsresult 1.144 +nsDocLoader::SetDocLoaderParent(nsDocLoader *aParent) 1.145 +{ 1.146 + mParent = aParent; 1.147 + return NS_OK; 1.148 +} 1.149 + 1.150 +nsresult 1.151 +nsDocLoader::Init() 1.152 +{ 1.153 + if (!mRequestInfoHash.ops) { 1.154 + return NS_ERROR_OUT_OF_MEMORY; 1.155 + } 1.156 + 1.157 + nsresult rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), this); 1.158 + if (NS_FAILED(rv)) return rv; 1.159 + 1.160 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.161 + ("DocLoader:%p: load group %x.\n", this, mLoadGroup.get())); 1.162 + 1.163 + return NS_OK; 1.164 +} 1.165 + 1.166 +nsDocLoader::~nsDocLoader() 1.167 +{ 1.168 + /* 1.169 + |ClearWeakReferences()| here is intended to prevent people holding weak references 1.170 + from re-entering this destructor since |QueryReferent()| will |AddRef()| me, and the 1.171 + subsequent |Release()| will try to destroy me. At this point there should be only 1.172 + weak references remaining (otherwise, we wouldn't be getting destroyed). 1.173 + 1.174 + An alternative would be incrementing our refcount (consider it a compressed flag 1.175 + saying "Don't re-destroy."). I haven't yet decided which is better. [scc] 1.176 + */ 1.177 + // XXXbz now that NS_IMPL_RELEASE stabilizes by setting refcount to 1, is 1.178 + // this needed? 1.179 + ClearWeakReferences(); 1.180 + 1.181 + Destroy(); 1.182 + 1.183 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.184 + ("DocLoader:%p: deleted.\n", this)); 1.185 + 1.186 + if (mRequestInfoHash.ops) { 1.187 + PL_DHashTableFinish(&mRequestInfoHash); 1.188 + } 1.189 +} 1.190 + 1.191 + 1.192 +/* 1.193 + * Implementation of ISupports methods... 1.194 + */ 1.195 +NS_IMPL_ADDREF(nsDocLoader) 1.196 +NS_IMPL_RELEASE(nsDocLoader) 1.197 + 1.198 +NS_INTERFACE_MAP_BEGIN(nsDocLoader) 1.199 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequestObserver) 1.200 + NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) 1.201 + NS_INTERFACE_MAP_ENTRY(nsIDocumentLoader) 1.202 + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 1.203 + NS_INTERFACE_MAP_ENTRY(nsIWebProgress) 1.204 + NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink) 1.205 + NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) 1.206 + NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink) 1.207 + NS_INTERFACE_MAP_ENTRY(nsISecurityEventSink) 1.208 + NS_INTERFACE_MAP_ENTRY(nsISupportsPriority) 1.209 + if (aIID.Equals(kThisImplCID)) 1.210 + foundInterface = static_cast<nsIDocumentLoader *>(this); 1.211 + else 1.212 +NS_INTERFACE_MAP_END 1.213 + 1.214 + 1.215 +/* 1.216 + * Implementation of nsIInterfaceRequestor methods... 1.217 + */ 1.218 +NS_IMETHODIMP nsDocLoader::GetInterface(const nsIID& aIID, void** aSink) 1.219 +{ 1.220 + nsresult rv = NS_ERROR_NO_INTERFACE; 1.221 + 1.222 + NS_ENSURE_ARG_POINTER(aSink); 1.223 + 1.224 + if(aIID.Equals(NS_GET_IID(nsILoadGroup))) { 1.225 + *aSink = mLoadGroup; 1.226 + NS_IF_ADDREF((nsISupports*)*aSink); 1.227 + rv = NS_OK; 1.228 + } else { 1.229 + rv = QueryInterface(aIID, aSink); 1.230 + } 1.231 + 1.232 + return rv; 1.233 +} 1.234 + 1.235 +/* static */ 1.236 +already_AddRefed<nsDocLoader> 1.237 +nsDocLoader::GetAsDocLoader(nsISupports* aSupports) 1.238 +{ 1.239 + nsRefPtr<nsDocLoader> ret = do_QueryObject(aSupports); 1.240 + return ret.forget(); 1.241 +} 1.242 + 1.243 +/* static */ 1.244 +nsresult 1.245 +nsDocLoader::AddDocLoaderAsChildOfRoot(nsDocLoader* aDocLoader) 1.246 +{ 1.247 + nsresult rv; 1.248 + nsCOMPtr<nsIDocumentLoader> docLoaderService = 1.249 + do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID, &rv); 1.250 + NS_ENSURE_SUCCESS(rv, rv); 1.251 + 1.252 + nsRefPtr<nsDocLoader> rootDocLoader = GetAsDocLoader(docLoaderService); 1.253 + NS_ENSURE_TRUE(rootDocLoader, NS_ERROR_UNEXPECTED); 1.254 + 1.255 + return rootDocLoader->AddChildLoader(aDocLoader); 1.256 +} 1.257 + 1.258 +NS_IMETHODIMP 1.259 +nsDocLoader::Stop(void) 1.260 +{ 1.261 + nsresult rv = NS_OK; 1.262 + 1.263 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.264 + ("DocLoader:%p: Stop() called\n", this)); 1.265 + 1.266 + NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList, nsDocLoader, Stop, ()); 1.267 + 1.268 + if (mLoadGroup) 1.269 + rv = mLoadGroup->Cancel(NS_BINDING_ABORTED); 1.270 + 1.271 + // Don't report that we're flushing layout so IsBusy returns false after a 1.272 + // Stop call. 1.273 + mIsFlushingLayout = false; 1.274 + 1.275 + // Clear out mChildrenInOnload. We want to make sure to fire our 1.276 + // onload at this point, and there's no issue with mChildrenInOnload 1.277 + // after this, since mDocumentRequest will be null after the 1.278 + // DocLoaderIsEmpty() call. 1.279 + mChildrenInOnload.Clear(); 1.280 + 1.281 + // Make sure to call DocLoaderIsEmpty now so that we reset mDocumentRequest, 1.282 + // etc, as needed. We could be getting into here from a subframe onload, in 1.283 + // which case the call to DocLoaderIsEmpty() is coming but hasn't quite 1.284 + // happened yet, Canceling the loadgroup did nothing (because it was already 1.285 + // empty), and we're about to start a new load (which is what triggered this 1.286 + // Stop() call). 1.287 + 1.288 + // XXXbz If the child frame loadgroups were requests in mLoadgroup, I suspect 1.289 + // we wouldn't need the call here.... 1.290 + 1.291 + NS_ASSERTION(!IsBusy(), "Shouldn't be busy here"); 1.292 + DocLoaderIsEmpty(false); 1.293 + 1.294 + return rv; 1.295 +} 1.296 + 1.297 + 1.298 +bool 1.299 +nsDocLoader::IsBusy() 1.300 +{ 1.301 + nsresult rv; 1.302 + 1.303 + // 1.304 + // A document loader is busy if either: 1.305 + // 1.306 + // 1. One of its children is in the middle of an onload handler. Note that 1.307 + // the handler may have already removed this child from mChildList! 1.308 + // 2. It is currently loading a document and either has parts of it still 1.309 + // loading, or has a busy child docloader. 1.310 + // 3. It's currently flushing layout in DocLoaderIsEmpty(). 1.311 + // 1.312 + 1.313 + if (mChildrenInOnload.Count() || mIsFlushingLayout) { 1.314 + return true; 1.315 + } 1.316 + 1.317 + /* Is this document loader busy? */ 1.318 + if (!mIsLoadingDocument) { 1.319 + return false; 1.320 + } 1.321 + 1.322 + bool busy; 1.323 + rv = mLoadGroup->IsPending(&busy); 1.324 + if (NS_FAILED(rv)) { 1.325 + return false; 1.326 + } 1.327 + if (busy) { 1.328 + return true; 1.329 + } 1.330 + 1.331 + /* check its child document loaders... */ 1.332 + uint32_t count = mChildList.Length(); 1.333 + for (uint32_t i=0; i < count; i++) { 1.334 + nsIDocumentLoader* loader = ChildAt(i); 1.335 + 1.336 + // This is a safe cast, because we only put nsDocLoader objects into the 1.337 + // array 1.338 + if (loader && static_cast<nsDocLoader*>(loader)->IsBusy()) 1.339 + return true; 1.340 + } 1.341 + 1.342 + return false; 1.343 +} 1.344 + 1.345 +NS_IMETHODIMP 1.346 +nsDocLoader::GetContainer(nsISupports** aResult) 1.347 +{ 1.348 + NS_ADDREF(*aResult = static_cast<nsIDocumentLoader*>(this)); 1.349 + 1.350 + return NS_OK; 1.351 +} 1.352 + 1.353 +NS_IMETHODIMP 1.354 +nsDocLoader::GetLoadGroup(nsILoadGroup** aResult) 1.355 +{ 1.356 + nsresult rv = NS_OK; 1.357 + 1.358 + if (nullptr == aResult) { 1.359 + rv = NS_ERROR_NULL_POINTER; 1.360 + } else { 1.361 + *aResult = mLoadGroup; 1.362 + NS_IF_ADDREF(*aResult); 1.363 + } 1.364 + return rv; 1.365 +} 1.366 + 1.367 +void 1.368 +nsDocLoader::Destroy() 1.369 +{ 1.370 + Stop(); 1.371 + 1.372 + // Remove the document loader from the parent list of loaders... 1.373 + if (mParent) 1.374 + { 1.375 + mParent->RemoveChildLoader(this); 1.376 + } 1.377 + 1.378 + // Release all the information about network requests... 1.379 + ClearRequestInfoHash(); 1.380 + 1.381 + // Release all the information about registered listeners... 1.382 + int32_t count = mListenerInfoList.Count(); 1.383 + for(int32_t i = 0; i < count; i++) { 1.384 + nsListenerInfo *info = 1.385 + static_cast<nsListenerInfo*>(mListenerInfoList.ElementAt(i)); 1.386 + 1.387 + delete info; 1.388 + } 1.389 + 1.390 + mListenerInfoList.Clear(); 1.391 + mListenerInfoList.Compact(); 1.392 + 1.393 + mDocumentRequest = 0; 1.394 + 1.395 + if (mLoadGroup) 1.396 + mLoadGroup->SetGroupObserver(nullptr); 1.397 + 1.398 + DestroyChildren(); 1.399 +} 1.400 + 1.401 +void 1.402 +nsDocLoader::DestroyChildren() 1.403 +{ 1.404 + uint32_t count = mChildList.Length(); 1.405 + // if the doc loader still has children...we need to enumerate the 1.406 + // children and make them null out their back ptr to the parent doc 1.407 + // loader 1.408 + for (uint32_t i=0; i < count; i++) 1.409 + { 1.410 + nsIDocumentLoader* loader = ChildAt(i); 1.411 + 1.412 + if (loader) { 1.413 + // This is a safe cast, as we only put nsDocLoader objects into the 1.414 + // array 1.415 + static_cast<nsDocLoader*>(loader)->SetDocLoaderParent(nullptr); 1.416 + } 1.417 + } 1.418 + mChildList.Clear(); 1.419 +} 1.420 + 1.421 +NS_IMETHODIMP 1.422 +nsDocLoader::OnStartRequest(nsIRequest *request, nsISupports *aCtxt) 1.423 +{ 1.424 + // called each time a request is added to the group. 1.425 + 1.426 +#ifdef PR_LOGGING 1.427 + if (PR_LOG_TEST(gDocLoaderLog, PR_LOG_DEBUG)) { 1.428 + nsAutoCString name; 1.429 + request->GetName(name); 1.430 + 1.431 + uint32_t count = 0; 1.432 + if (mLoadGroup) 1.433 + mLoadGroup->GetActiveCount(&count); 1.434 + 1.435 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.436 + ("DocLoader:%p: OnStartRequest[%p](%s) mIsLoadingDocument=%s, %u active URLs", 1.437 + this, request, name.get(), 1.438 + (mIsLoadingDocument ? "true" : "false"), 1.439 + count)); 1.440 + } 1.441 +#endif /* PR_LOGGING */ 1.442 + bool bJustStartedLoading = false; 1.443 + 1.444 + nsLoadFlags loadFlags = 0; 1.445 + request->GetLoadFlags(&loadFlags); 1.446 + 1.447 + if (!mIsLoadingDocument && (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)) { 1.448 + bJustStartedLoading = true; 1.449 + mIsLoadingDocument = true; 1.450 + ClearInternalProgress(); // only clear our progress if we are starting a new load.... 1.451 + } 1.452 + 1.453 + // 1.454 + // Create a new nsRequestInfo for the request that is starting to 1.455 + // load... 1.456 + // 1.457 + AddRequestInfo(request); 1.458 + 1.459 + // 1.460 + // Only fire a doStartDocumentLoad(...) if the document loader 1.461 + // has initiated a load... Otherwise, this notification has 1.462 + // resulted from a request being added to the load group. 1.463 + // 1.464 + if (mIsLoadingDocument) { 1.465 + if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) { 1.466 + // 1.467 + // Make sure that the document channel is null at this point... 1.468 + // (unless its been redirected) 1.469 + // 1.470 + NS_ASSERTION((loadFlags & nsIChannel::LOAD_REPLACE) || 1.471 + !(mDocumentRequest.get()), 1.472 + "Overwriting an existing document channel!"); 1.473 + 1.474 + // This request is associated with the entire document... 1.475 + mDocumentRequest = request; 1.476 + mLoadGroup->SetDefaultLoadRequest(request); 1.477 + 1.478 + // Only fire the start document load notification for the first 1.479 + // document URI... Do not fire it again for redirections 1.480 + // 1.481 + if (bJustStartedLoading) { 1.482 + // Update the progress status state 1.483 + mProgressStateFlags = nsIWebProgressListener::STATE_START; 1.484 + 1.485 + // Fire the start document load notification 1.486 + doStartDocumentLoad(); 1.487 + return NS_OK; 1.488 + } 1.489 + } 1.490 + } 1.491 + 1.492 + NS_ASSERTION(!mIsLoadingDocument || mDocumentRequest, 1.493 + "mDocumentRequest MUST be set for the duration of a page load!"); 1.494 + 1.495 + doStartURLLoad(request); 1.496 + 1.497 + return NS_OK; 1.498 +} 1.499 + 1.500 +NS_IMETHODIMP 1.501 +nsDocLoader::OnStopRequest(nsIRequest *aRequest, 1.502 + nsISupports *aCtxt, 1.503 + nsresult aStatus) 1.504 +{ 1.505 + nsresult rv = NS_OK; 1.506 + 1.507 +#ifdef PR_LOGGING 1.508 + if (PR_LOG_TEST(gDocLoaderLog, PR_LOG_DEBUG)) { 1.509 + nsAutoCString name; 1.510 + aRequest->GetName(name); 1.511 + 1.512 + uint32_t count = 0; 1.513 + if (mLoadGroup) 1.514 + mLoadGroup->GetActiveCount(&count); 1.515 + 1.516 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.517 + ("DocLoader:%p: OnStopRequest[%p](%s) status=%x mIsLoadingDocument=%s, %u active URLs", 1.518 + this, aRequest, name.get(), 1.519 + aStatus, (mIsLoadingDocument ? "true" : "false"), 1.520 + count)); 1.521 + } 1.522 +#endif 1.523 + 1.524 + bool bFireTransferring = false; 1.525 + 1.526 + // 1.527 + // Set the Maximum progress to the same value as the current progress. 1.528 + // Since the URI has finished loading, all the data is there. Also, 1.529 + // this will allow a more accurate estimation of the max progress (in case 1.530 + // the old value was unknown ie. -1) 1.531 + // 1.532 + nsRequestInfo *info = GetRequestInfo(aRequest); 1.533 + if (info) { 1.534 + // Null out mLastStatus now so we don't find it when looking for 1.535 + // status from now on. This destroys the nsStatusInfo and hence 1.536 + // removes it from our list. 1.537 + info->mLastStatus = nullptr; 1.538 + 1.539 + int64_t oldMax = info->mMaxProgress; 1.540 + 1.541 + info->mMaxProgress = info->mCurrentProgress; 1.542 + 1.543 + // 1.544 + // If a request whose content-length was previously unknown has just 1.545 + // finished loading, then use this new data to try to calculate a 1.546 + // mMaxSelfProgress... 1.547 + // 1.548 + if ((oldMax < int64_t(0)) && (mMaxSelfProgress < int64_t(0))) { 1.549 + mMaxSelfProgress = CalculateMaxProgress(); 1.550 + } 1.551 + 1.552 + // As we know the total progress of this request now, save it to be part 1.553 + // of CalculateMaxProgress() result. We need to remove the info from the 1.554 + // hash, see bug 480713. 1.555 + mCompletedTotalProgress += info->mMaxProgress; 1.556 + 1.557 + // 1.558 + // Determine whether a STATE_TRANSFERRING notification should be 1.559 + // 'synthesized'. 1.560 + // 1.561 + // If nsRequestInfo::mMaxProgress (as stored in oldMax) and 1.562 + // nsRequestInfo::mCurrentProgress are both 0, then the 1.563 + // STATE_TRANSFERRING notification has not been fired yet... 1.564 + // 1.565 + if ((oldMax == 0) && (info->mCurrentProgress == 0)) { 1.566 + nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); 1.567 + 1.568 + // Only fire a TRANSFERRING notification if the request is also a 1.569 + // channel -- data transfer requires a nsIChannel! 1.570 + // 1.571 + if (channel) { 1.572 + if (NS_SUCCEEDED(aStatus)) { 1.573 + bFireTransferring = true; 1.574 + } 1.575 + // 1.576 + // If the request failed (for any reason other than being 1.577 + // redirected or retargeted), the TRANSFERRING notification can 1.578 + // still be fired if a HTTP connection was established to a server. 1.579 + // 1.580 + else if (aStatus != NS_BINDING_REDIRECTED && 1.581 + aStatus != NS_BINDING_RETARGETED) { 1.582 + // 1.583 + // Only if the load has been targeted (see bug 268483)... 1.584 + // 1.585 + uint32_t lf; 1.586 + channel->GetLoadFlags(&lf); 1.587 + if (lf & nsIChannel::LOAD_TARGETED) { 1.588 + nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest)); 1.589 + if (httpChannel) { 1.590 + uint32_t responseCode; 1.591 + rv = httpChannel->GetResponseStatus(&responseCode); 1.592 + if (NS_SUCCEEDED(rv)) { 1.593 + // 1.594 + // A valid server status indicates that a connection was 1.595 + // established to the server... So, fire the notification 1.596 + // even though a failure occurred later... 1.597 + // 1.598 + bFireTransferring = true; 1.599 + } 1.600 + } 1.601 + } 1.602 + } 1.603 + } 1.604 + } 1.605 + } 1.606 + 1.607 + if (bFireTransferring) { 1.608 + // Send a STATE_TRANSFERRING notification for the request. 1.609 + int32_t flags; 1.610 + 1.611 + flags = nsIWebProgressListener::STATE_TRANSFERRING | 1.612 + nsIWebProgressListener::STATE_IS_REQUEST; 1.613 + // 1.614 + // Move the WebProgress into the STATE_TRANSFERRING state if necessary... 1.615 + // 1.616 + if (mProgressStateFlags & nsIWebProgressListener::STATE_START) { 1.617 + mProgressStateFlags = nsIWebProgressListener::STATE_TRANSFERRING; 1.618 + 1.619 + // Send STATE_TRANSFERRING for the document too... 1.620 + flags |= nsIWebProgressListener::STATE_IS_DOCUMENT; 1.621 + } 1.622 + 1.623 + FireOnStateChange(this, aRequest, flags, NS_OK); 1.624 + } 1.625 + 1.626 + // 1.627 + // Fire the OnStateChange(...) notification for stop request 1.628 + // 1.629 + doStopURLLoad(aRequest, aStatus); 1.630 + 1.631 + // Clear this request out of the hash to avoid bypass of FireOnStateChange 1.632 + // when address of the request is reused. 1.633 + RemoveRequestInfo(aRequest); 1.634 + 1.635 + // 1.636 + // Only fire the DocLoaderIsEmpty(...) if the document loader has initiated a 1.637 + // load. This will handle removing the request from our hashtable as needed. 1.638 + // 1.639 + if (mIsLoadingDocument) { 1.640 + DocLoaderIsEmpty(true); 1.641 + } 1.642 + 1.643 + return NS_OK; 1.644 +} 1.645 + 1.646 + 1.647 +nsresult nsDocLoader::RemoveChildLoader(nsDocLoader* aChild) 1.648 +{ 1.649 + nsresult rv = mChildList.RemoveElement(aChild) ? NS_OK : NS_ERROR_FAILURE; 1.650 + if (NS_SUCCEEDED(rv)) { 1.651 + aChild->SetDocLoaderParent(nullptr); 1.652 + } 1.653 + return rv; 1.654 +} 1.655 + 1.656 +nsresult nsDocLoader::AddChildLoader(nsDocLoader* aChild) 1.657 +{ 1.658 + nsresult rv = mChildList.AppendElement(aChild) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; 1.659 + if (NS_SUCCEEDED(rv)) { 1.660 + aChild->SetDocLoaderParent(this); 1.661 + } 1.662 + return rv; 1.663 +} 1.664 + 1.665 +NS_IMETHODIMP nsDocLoader::GetDocumentChannel(nsIChannel ** aChannel) 1.666 +{ 1.667 + if (!mDocumentRequest) { 1.668 + *aChannel = nullptr; 1.669 + return NS_OK; 1.670 + } 1.671 + 1.672 + return CallQueryInterface(mDocumentRequest, aChannel); 1.673 +} 1.674 + 1.675 + 1.676 +void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout) 1.677 +{ 1.678 + if (mIsLoadingDocument) { 1.679 + /* In the unimagineably rude circumstance that onload event handlers 1.680 + triggered by this function actually kill the window ... ok, it's 1.681 + not unimagineable; it's happened ... this deathgrip keeps this object 1.682 + alive long enough to survive this function call. */ 1.683 + nsCOMPtr<nsIDocumentLoader> kungFuDeathGrip(this); 1.684 + 1.685 + // Don't flush layout if we're still busy. 1.686 + if (IsBusy()) { 1.687 + return; 1.688 + } 1.689 + 1.690 + NS_ASSERTION(!mIsFlushingLayout, "Someone screwed up"); 1.691 + 1.692 + // The load group for this DocumentLoader is idle. Flush if we need to. 1.693 + if (aFlushLayout && !mDontFlushLayout) { 1.694 + nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(GetAsSupports(this)); 1.695 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); 1.696 + if (doc) { 1.697 + // We start loads from style resolution, so we need to flush out style 1.698 + // no matter what. If we have user fonts, we also need to flush layout, 1.699 + // since the reflow is what starts font loads. 1.700 + mozFlushType flushType = Flush_Style; 1.701 + nsIPresShell* shell = doc->GetShell(); 1.702 + if (shell) { 1.703 + // Be safe in case this presshell is in teardown now 1.704 + nsPresContext* presContext = shell->GetPresContext(); 1.705 + if (presContext && presContext->GetUserFontSet()) { 1.706 + flushType = Flush_Layout; 1.707 + } 1.708 + } 1.709 + mDontFlushLayout = mIsFlushingLayout = true; 1.710 + doc->FlushPendingNotifications(flushType); 1.711 + mDontFlushLayout = mIsFlushingLayout = false; 1.712 + } 1.713 + } 1.714 + 1.715 + // And now check whether we're really busy; that might have changed with 1.716 + // the layout flush. 1.717 + if (!IsBusy()) { 1.718 + // Clear out our request info hash, now that our load really is done and 1.719 + // we don't need it anymore to CalculateMaxProgress(). 1.720 + ClearInternalProgress(); 1.721 + 1.722 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.723 + ("DocLoader:%p: Is now idle...\n", this)); 1.724 + 1.725 + nsCOMPtr<nsIRequest> docRequest = mDocumentRequest; 1.726 + 1.727 + NS_ASSERTION(mDocumentRequest, "No Document Request!"); 1.728 + mDocumentRequest = 0; 1.729 + mIsLoadingDocument = false; 1.730 + 1.731 + // Update the progress status state - the document is done 1.732 + mProgressStateFlags = nsIWebProgressListener::STATE_STOP; 1.733 + 1.734 + 1.735 + nsresult loadGroupStatus = NS_OK; 1.736 + mLoadGroup->GetStatus(&loadGroupStatus); 1.737 + 1.738 + // 1.739 + // New code to break the circular reference between 1.740 + // the load group and the docloader... 1.741 + // 1.742 + mLoadGroup->SetDefaultLoadRequest(nullptr); 1.743 + 1.744 + // Take a ref to our parent now so that we can call DocLoaderIsEmpty() on 1.745 + // it even if our onload handler removes us from the docloader tree. 1.746 + nsRefPtr<nsDocLoader> parent = mParent; 1.747 + 1.748 + // Note that if calling ChildEnteringOnload() on the parent returns false 1.749 + // then calling our onload handler is not safe. That can only happen on 1.750 + // OOM, so that's ok. 1.751 + if (!parent || parent->ChildEnteringOnload(this)) { 1.752 + // Do nothing with our state after firing the 1.753 + // OnEndDocumentLoad(...). The document loader may be loading a *new* 1.754 + // document - if LoadDocument() was called from a handler! 1.755 + // 1.756 + doStopDocumentLoad(docRequest, loadGroupStatus); 1.757 + 1.758 + if (parent) { 1.759 + parent->ChildDoneWithOnload(this); 1.760 + } 1.761 + } 1.762 + } 1.763 + } 1.764 +} 1.765 + 1.766 +void nsDocLoader::doStartDocumentLoad(void) 1.767 +{ 1.768 + 1.769 +#if defined(DEBUG) 1.770 + nsAutoCString buffer; 1.771 + 1.772 + GetURIStringFromRequest(mDocumentRequest, buffer); 1.773 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.774 + ("DocLoader:%p: ++ Firing OnStateChange for start document load (...)." 1.775 + "\tURI: %s \n", 1.776 + this, buffer.get())); 1.777 +#endif /* DEBUG */ 1.778 + 1.779 + // Fire an OnStatus(...) notification STATE_START. This indicates 1.780 + // that the document represented by mDocumentRequest has started to 1.781 + // load... 1.782 + FireOnStateChange(this, 1.783 + mDocumentRequest, 1.784 + nsIWebProgressListener::STATE_START | 1.785 + nsIWebProgressListener::STATE_IS_DOCUMENT | 1.786 + nsIWebProgressListener::STATE_IS_REQUEST | 1.787 + nsIWebProgressListener::STATE_IS_WINDOW | 1.788 + nsIWebProgressListener::STATE_IS_NETWORK, 1.789 + NS_OK); 1.790 +} 1.791 + 1.792 +void nsDocLoader::doStartURLLoad(nsIRequest *request) 1.793 +{ 1.794 +#if defined(DEBUG) 1.795 + nsAutoCString buffer; 1.796 + 1.797 + GetURIStringFromRequest(request, buffer); 1.798 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.799 + ("DocLoader:%p: ++ Firing OnStateChange start url load (...)." 1.800 + "\tURI: %s\n", 1.801 + this, buffer.get())); 1.802 +#endif /* DEBUG */ 1.803 + 1.804 + FireOnStateChange(this, 1.805 + request, 1.806 + nsIWebProgressListener::STATE_START | 1.807 + nsIWebProgressListener::STATE_IS_REQUEST, 1.808 + NS_OK); 1.809 +} 1.810 + 1.811 +void nsDocLoader::doStopURLLoad(nsIRequest *request, nsresult aStatus) 1.812 +{ 1.813 +#if defined(DEBUG) 1.814 + nsAutoCString buffer; 1.815 + 1.816 + GetURIStringFromRequest(request, buffer); 1.817 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.818 + ("DocLoader:%p: ++ Firing OnStateChange for end url load (...)." 1.819 + "\tURI: %s status=%x\n", 1.820 + this, buffer.get(), aStatus)); 1.821 +#endif /* DEBUG */ 1.822 + 1.823 + FireOnStateChange(this, 1.824 + request, 1.825 + nsIWebProgressListener::STATE_STOP | 1.826 + nsIWebProgressListener::STATE_IS_REQUEST, 1.827 + aStatus); 1.828 + 1.829 + // Fire a status change message for the most recent unfinished 1.830 + // request to make sure that the displayed status is not outdated. 1.831 + if (!mStatusInfoList.isEmpty()) { 1.832 + nsStatusInfo* statusInfo = mStatusInfoList.getFirst(); 1.833 + FireOnStatusChange(this, statusInfo->mRequest, 1.834 + statusInfo->mStatusCode, 1.835 + statusInfo->mStatusMessage.get()); 1.836 + } 1.837 +} 1.838 + 1.839 +void nsDocLoader::doStopDocumentLoad(nsIRequest *request, 1.840 + nsresult aStatus) 1.841 +{ 1.842 +#if defined(DEBUG) 1.843 + nsAutoCString buffer; 1.844 + 1.845 + GetURIStringFromRequest(request, buffer); 1.846 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.847 + ("DocLoader:%p: ++ Firing OnStateChange for end document load (...)." 1.848 + "\tURI: %s Status=%x\n", 1.849 + this, buffer.get(), aStatus)); 1.850 +#endif /* DEBUG */ 1.851 + 1.852 + // Firing STATE_STOP|STATE_IS_DOCUMENT will fire onload handlers. 1.853 + // Grab our parent chain before doing that so we can still dispatch 1.854 + // STATE_STOP|STATE_IS_WINDW_STATE_IS_NETWORK to them all, even if 1.855 + // the onload handlers rearrange the docshell tree. 1.856 + WebProgressList list; 1.857 + GatherAncestorWebProgresses(list); 1.858 + 1.859 + // 1.860 + // Fire an OnStateChange(...) notification indicating the the 1.861 + // current document has finished loading... 1.862 + // 1.863 + int32_t flags = nsIWebProgressListener::STATE_STOP | 1.864 + nsIWebProgressListener::STATE_IS_DOCUMENT; 1.865 + for (uint32_t i = 0; i < list.Length(); ++i) { 1.866 + list[i]->DoFireOnStateChange(this, request, flags, aStatus); 1.867 + } 1.868 + 1.869 + // 1.870 + // Fire a final OnStateChange(...) notification indicating the the 1.871 + // current document has finished loading... 1.872 + // 1.873 + flags = nsIWebProgressListener::STATE_STOP | 1.874 + nsIWebProgressListener::STATE_IS_WINDOW | 1.875 + nsIWebProgressListener::STATE_IS_NETWORK; 1.876 + for (uint32_t i = 0; i < list.Length(); ++i) { 1.877 + list[i]->DoFireOnStateChange(this, request, flags, aStatus); 1.878 + } 1.879 +} 1.880 + 1.881 +//////////////////////////////////////////////////////////////////////////////////// 1.882 +// The following section contains support for nsIWebProgress and related stuff 1.883 +//////////////////////////////////////////////////////////////////////////////////// 1.884 + 1.885 +NS_IMETHODIMP 1.886 +nsDocLoader::AddProgressListener(nsIWebProgressListener *aListener, 1.887 + uint32_t aNotifyMask) 1.888 +{ 1.889 + nsresult rv; 1.890 + 1.891 + nsListenerInfo* info = GetListenerInfo(aListener); 1.892 + if (info) { 1.893 + // The listener is already registered! 1.894 + return NS_ERROR_FAILURE; 1.895 + } 1.896 + 1.897 + nsWeakPtr listener = do_GetWeakReference(aListener); 1.898 + if (!listener) { 1.899 + return NS_ERROR_INVALID_ARG; 1.900 + } 1.901 + 1.902 + info = new nsListenerInfo(listener, aNotifyMask); 1.903 + if (!info) { 1.904 + return NS_ERROR_OUT_OF_MEMORY; 1.905 + } 1.906 + 1.907 + rv = mListenerInfoList.AppendElement(info) ? NS_OK : NS_ERROR_FAILURE; 1.908 + return rv; 1.909 +} 1.910 + 1.911 +NS_IMETHODIMP 1.912 +nsDocLoader::RemoveProgressListener(nsIWebProgressListener *aListener) 1.913 +{ 1.914 + nsresult rv; 1.915 + 1.916 + nsListenerInfo* info = GetListenerInfo(aListener); 1.917 + if (info) { 1.918 + rv = mListenerInfoList.RemoveElement(info) ? NS_OK : NS_ERROR_FAILURE; 1.919 + delete info; 1.920 + } else { 1.921 + // The listener is not registered! 1.922 + rv = NS_ERROR_FAILURE; 1.923 + } 1.924 + return rv; 1.925 +} 1.926 + 1.927 +NS_IMETHODIMP 1.928 +nsDocLoader::GetDOMWindow(nsIDOMWindow **aResult) 1.929 +{ 1.930 + return CallGetInterface(this, aResult); 1.931 +} 1.932 + 1.933 +NS_IMETHODIMP 1.934 +nsDocLoader::GetDOMWindowID(uint64_t *aResult) 1.935 +{ 1.936 + *aResult = 0; 1.937 + 1.938 + nsCOMPtr<nsIDOMWindow> window; 1.939 + nsresult rv = GetDOMWindow(getter_AddRefs(window)); 1.940 + NS_ENSURE_SUCCESS(rv, rv); 1.941 + 1.942 + nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(window); 1.943 + NS_ENSURE_STATE(piwindow); 1.944 + 1.945 + MOZ_ASSERT(piwindow->IsOuterWindow()); 1.946 + *aResult = piwindow->WindowID(); 1.947 + return NS_OK; 1.948 +} 1.949 + 1.950 +NS_IMETHODIMP 1.951 +nsDocLoader::GetIsTopLevel(bool *aResult) 1.952 +{ 1.953 + *aResult = false; 1.954 + 1.955 + nsCOMPtr<nsIDOMWindow> window; 1.956 + GetDOMWindow(getter_AddRefs(window)); 1.957 + if (window) { 1.958 + nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(window); 1.959 + NS_ENSURE_STATE(piwindow); 1.960 + 1.961 + nsCOMPtr<nsIDOMWindow> topWindow; 1.962 + nsresult rv = piwindow->GetTop(getter_AddRefs(topWindow)); 1.963 + NS_ENSURE_SUCCESS(rv, rv); 1.964 + 1.965 + *aResult = piwindow == topWindow; 1.966 + } 1.967 + 1.968 + return NS_OK; 1.969 +} 1.970 + 1.971 +NS_IMETHODIMP 1.972 +nsDocLoader::GetIsLoadingDocument(bool *aIsLoadingDocument) 1.973 +{ 1.974 + *aIsLoadingDocument = mIsLoadingDocument; 1.975 + 1.976 + return NS_OK; 1.977 +} 1.978 + 1.979 +NS_IMETHODIMP 1.980 +nsDocLoader::GetLoadType(uint32_t *aLoadType) 1.981 +{ 1.982 + *aLoadType = 0; 1.983 + 1.984 + return NS_ERROR_NOT_IMPLEMENTED; 1.985 +} 1.986 + 1.987 +int64_t nsDocLoader::GetMaxTotalProgress() 1.988 +{ 1.989 + int64_t newMaxTotal = 0; 1.990 + 1.991 + uint32_t count = mChildList.Length(); 1.992 + nsCOMPtr<nsIWebProgress> webProgress; 1.993 + for (uint32_t i=0; i < count; i++) 1.994 + { 1.995 + int64_t individualProgress = 0; 1.996 + nsIDocumentLoader* docloader = ChildAt(i); 1.997 + if (docloader) 1.998 + { 1.999 + // Cast is safe since all children are nsDocLoader too 1.1000 + individualProgress = ((nsDocLoader *) docloader)->GetMaxTotalProgress(); 1.1001 + } 1.1002 + if (individualProgress < int64_t(0)) // if one of the elements doesn't know it's size 1.1003 + // then none of them do 1.1004 + { 1.1005 + newMaxTotal = int64_t(-1); 1.1006 + break; 1.1007 + } 1.1008 + else 1.1009 + newMaxTotal += individualProgress; 1.1010 + } 1.1011 + 1.1012 + int64_t progress = -1; 1.1013 + if (mMaxSelfProgress >= int64_t(0) && newMaxTotal >= int64_t(0)) 1.1014 + progress = newMaxTotal + mMaxSelfProgress; 1.1015 + 1.1016 + return progress; 1.1017 +} 1.1018 + 1.1019 +//////////////////////////////////////////////////////////////////////////////////// 1.1020 +// The following section contains support for nsIProgressEventSink which is used to 1.1021 +// pass progress and status between the actual request and the doc loader. The doc loader 1.1022 +// then turns around and makes the right web progress calls based on this information. 1.1023 +//////////////////////////////////////////////////////////////////////////////////// 1.1024 + 1.1025 +NS_IMETHODIMP nsDocLoader::OnProgress(nsIRequest *aRequest, nsISupports* ctxt, 1.1026 + uint64_t aProgress, uint64_t aProgressMax) 1.1027 +{ 1.1028 + int64_t progressDelta = 0; 1.1029 + 1.1030 + // 1.1031 + // Update the RequestInfo entry with the new progress data 1.1032 + // 1.1033 + if (nsRequestInfo* info = GetRequestInfo(aRequest)) { 1.1034 + // Update info->mCurrentProgress before we call FireOnStateChange, 1.1035 + // since that can make the "info" pointer invalid. 1.1036 + int64_t oldCurrentProgress = info->mCurrentProgress; 1.1037 + progressDelta = int64_t(aProgress) - oldCurrentProgress; 1.1038 + info->mCurrentProgress = int64_t(aProgress); 1.1039 + 1.1040 + // suppress sending STATE_TRANSFERRING if this is upload progress (see bug 240053) 1.1041 + if (!info->mUploading && (int64_t(0) == oldCurrentProgress) && (int64_t(0) == info->mMaxProgress)) { 1.1042 + // 1.1043 + // If we receive an OnProgress event from a toplevel channel that the URI Loader 1.1044 + // has not yet targeted, then we must suppress the event. This is necessary to 1.1045 + // ensure that webprogresslisteners do not get confused when the channel is 1.1046 + // finally targeted. See bug 257308. 1.1047 + // 1.1048 + nsLoadFlags lf = 0; 1.1049 + aRequest->GetLoadFlags(&lf); 1.1050 + if ((lf & nsIChannel::LOAD_DOCUMENT_URI) && !(lf & nsIChannel::LOAD_TARGETED)) { 1.1051 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.1052 + ("DocLoader:%p Ignoring OnProgress while load is not targeted\n", this)); 1.1053 + return NS_OK; 1.1054 + } 1.1055 + 1.1056 + // 1.1057 + // This is the first progress notification for the entry. If 1.1058 + // (aMaxProgress > 0) then the content-length of the data is known, 1.1059 + // so update mMaxSelfProgress... Otherwise, set it to -1 to indicate 1.1060 + // that the content-length is no longer known. 1.1061 + // 1.1062 + if (uint64_t(aProgressMax) != UINT64_MAX) { 1.1063 + mMaxSelfProgress += int64_t(aProgressMax); 1.1064 + info->mMaxProgress = int64_t(aProgressMax); 1.1065 + } else { 1.1066 + mMaxSelfProgress = int64_t(-1); 1.1067 + info->mMaxProgress = int64_t(-1); 1.1068 + } 1.1069 + 1.1070 + // Send a STATE_TRANSFERRING notification for the request. 1.1071 + int32_t flags; 1.1072 + 1.1073 + flags = nsIWebProgressListener::STATE_TRANSFERRING | 1.1074 + nsIWebProgressListener::STATE_IS_REQUEST; 1.1075 + // 1.1076 + // Move the WebProgress into the STATE_TRANSFERRING state if necessary... 1.1077 + // 1.1078 + if (mProgressStateFlags & nsIWebProgressListener::STATE_START) { 1.1079 + mProgressStateFlags = nsIWebProgressListener::STATE_TRANSFERRING; 1.1080 + 1.1081 + // Send STATE_TRANSFERRING for the document too... 1.1082 + flags |= nsIWebProgressListener::STATE_IS_DOCUMENT; 1.1083 + } 1.1084 + 1.1085 + FireOnStateChange(this, aRequest, flags, NS_OK); 1.1086 + } 1.1087 + 1.1088 + // Update our overall current progress count. 1.1089 + mCurrentSelfProgress += progressDelta; 1.1090 + } 1.1091 + // 1.1092 + // The request is not part of the load group, so ignore its progress 1.1093 + // information... 1.1094 + // 1.1095 + else { 1.1096 +#if defined(DEBUG) 1.1097 + nsAutoCString buffer; 1.1098 + 1.1099 + GetURIStringFromRequest(aRequest, buffer); 1.1100 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.1101 + ("DocLoader:%p OOPS - No Request Info for: %s\n", 1.1102 + this, buffer.get())); 1.1103 +#endif /* DEBUG */ 1.1104 + 1.1105 + return NS_OK; 1.1106 + } 1.1107 + 1.1108 + // 1.1109 + // Fire progress notifications out to any registered nsIWebProgressListeners 1.1110 + // 1.1111 + FireOnProgressChange(this, aRequest, aProgress, aProgressMax, progressDelta, 1.1112 + mCurrentTotalProgress, mMaxTotalProgress); 1.1113 + 1.1114 + return NS_OK; 1.1115 +} 1.1116 + 1.1117 +NS_IMETHODIMP nsDocLoader::OnStatus(nsIRequest* aRequest, nsISupports* ctxt, 1.1118 + nsresult aStatus, const char16_t* aStatusArg) 1.1119 +{ 1.1120 + // 1.1121 + // Fire progress notifications out to any registered nsIWebProgressListeners 1.1122 + // 1.1123 + if (aStatus != NS_OK) { 1.1124 + // Remember the current status for this request 1.1125 + nsRequestInfo *info; 1.1126 + info = GetRequestInfo(aRequest); 1.1127 + if (info) { 1.1128 + bool uploading = (aStatus == NS_NET_STATUS_WRITING || 1.1129 + aStatus == NS_NET_STATUS_SENDING_TO); 1.1130 + // If switching from uploading to downloading (or vice versa), then we 1.1131 + // need to reset our progress counts. This is designed with HTTP form 1.1132 + // submission in mind, where an upload is performed followed by download 1.1133 + // of possibly several documents. 1.1134 + if (info->mUploading != uploading) { 1.1135 + mCurrentSelfProgress = mMaxSelfProgress = 0; 1.1136 + mCurrentTotalProgress = mMaxTotalProgress = 0; 1.1137 + mCompletedTotalProgress = 0; 1.1138 + info->mUploading = uploading; 1.1139 + info->mCurrentProgress = 0; 1.1140 + info->mMaxProgress = 0; 1.1141 + } 1.1142 + } 1.1143 + 1.1144 + nsCOMPtr<nsIStringBundleService> sbs = 1.1145 + mozilla::services::GetStringBundleService(); 1.1146 + if (!sbs) 1.1147 + return NS_ERROR_FAILURE; 1.1148 + nsXPIDLString msg; 1.1149 + nsresult rv = sbs->FormatStatusMessage(aStatus, aStatusArg, 1.1150 + getter_Copies(msg)); 1.1151 + if (NS_FAILED(rv)) 1.1152 + return rv; 1.1153 + 1.1154 + // Keep around the message. In case a request finishes, we need to make sure 1.1155 + // to send the status message of another request to our user to that we 1.1156 + // don't display, for example, "Transferring" messages for requests that are 1.1157 + // already done. 1.1158 + if (info) { 1.1159 + if (!info->mLastStatus) { 1.1160 + info->mLastStatus = new nsStatusInfo(aRequest); 1.1161 + } else { 1.1162 + // We're going to move it to the front of the list, so remove 1.1163 + // it from wherever it is now. 1.1164 + info->mLastStatus->remove(); 1.1165 + } 1.1166 + info->mLastStatus->mStatusMessage = msg; 1.1167 + info->mLastStatus->mStatusCode = aStatus; 1.1168 + // Put the info at the front of the list 1.1169 + mStatusInfoList.insertFront(info->mLastStatus); 1.1170 + } 1.1171 + FireOnStatusChange(this, aRequest, aStatus, msg); 1.1172 + } 1.1173 + return NS_OK; 1.1174 +} 1.1175 + 1.1176 +void nsDocLoader::ClearInternalProgress() 1.1177 +{ 1.1178 + ClearRequestInfoHash(); 1.1179 + 1.1180 + mCurrentSelfProgress = mMaxSelfProgress = 0; 1.1181 + mCurrentTotalProgress = mMaxTotalProgress = 0; 1.1182 + mCompletedTotalProgress = 0; 1.1183 + 1.1184 + mProgressStateFlags = nsIWebProgressListener::STATE_STOP; 1.1185 +} 1.1186 + 1.1187 + 1.1188 +void nsDocLoader::FireOnProgressChange(nsDocLoader *aLoadInitiator, 1.1189 + nsIRequest *request, 1.1190 + int64_t aProgress, 1.1191 + int64_t aProgressMax, 1.1192 + int64_t aProgressDelta, 1.1193 + int64_t aTotalProgress, 1.1194 + int64_t aMaxTotalProgress) 1.1195 +{ 1.1196 + if (mIsLoadingDocument) { 1.1197 + mCurrentTotalProgress += aProgressDelta; 1.1198 + mMaxTotalProgress = GetMaxTotalProgress(); 1.1199 + 1.1200 + aTotalProgress = mCurrentTotalProgress; 1.1201 + aMaxTotalProgress = mMaxTotalProgress; 1.1202 + } 1.1203 + 1.1204 +#if defined(DEBUG) 1.1205 + nsAutoCString buffer; 1.1206 + 1.1207 + GetURIStringFromRequest(request, buffer); 1.1208 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.1209 + ("DocLoader:%p: Progress (%s): curSelf: %d maxSelf: %d curTotal: %d maxTotal %d\n", 1.1210 + this, buffer.get(), aProgress, aProgressMax, aTotalProgress, aMaxTotalProgress)); 1.1211 +#endif /* DEBUG */ 1.1212 + 1.1213 + /* 1.1214 + * First notify any listeners of the new progress info... 1.1215 + * 1.1216 + * Operate the elements from back to front so that if items get 1.1217 + * get removed from the list it won't affect our iteration 1.1218 + */ 1.1219 + nsCOMPtr<nsIWebProgressListener> listener; 1.1220 + int32_t count = mListenerInfoList.Count(); 1.1221 + 1.1222 + while (--count >= 0) { 1.1223 + nsListenerInfo *info; 1.1224 + 1.1225 + info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count)); 1.1226 + if (!info || !(info->mNotifyMask & nsIWebProgress::NOTIFY_PROGRESS)) { 1.1227 + continue; 1.1228 + } 1.1229 + 1.1230 + listener = do_QueryReferent(info->mWeakListener); 1.1231 + if (!listener) { 1.1232 + // the listener went away. gracefully pull it out of the list. 1.1233 + mListenerInfoList.RemoveElementAt(count); 1.1234 + delete info; 1.1235 + continue; 1.1236 + } 1.1237 + 1.1238 + // XXX truncates 64-bit to 32-bit 1.1239 + listener->OnProgressChange(aLoadInitiator,request, 1.1240 + int32_t(aProgress), int32_t(aProgressMax), 1.1241 + int32_t(aTotalProgress), int32_t(aMaxTotalProgress)); 1.1242 + } 1.1243 + 1.1244 + mListenerInfoList.Compact(); 1.1245 + 1.1246 + // Pass the notification up to the parent... 1.1247 + if (mParent) { 1.1248 + mParent->FireOnProgressChange(aLoadInitiator, request, 1.1249 + aProgress, aProgressMax, 1.1250 + aProgressDelta, 1.1251 + aTotalProgress, aMaxTotalProgress); 1.1252 + } 1.1253 +} 1.1254 + 1.1255 +void nsDocLoader::GatherAncestorWebProgresses(WebProgressList& aList) 1.1256 +{ 1.1257 + for (nsDocLoader* loader = this; loader; loader = loader->mParent) { 1.1258 + aList.AppendElement(loader); 1.1259 + } 1.1260 +} 1.1261 + 1.1262 +void nsDocLoader::FireOnStateChange(nsIWebProgress *aProgress, 1.1263 + nsIRequest *aRequest, 1.1264 + int32_t aStateFlags, 1.1265 + nsresult aStatus) 1.1266 +{ 1.1267 + WebProgressList list; 1.1268 + GatherAncestorWebProgresses(list); 1.1269 + for (uint32_t i = 0; i < list.Length(); ++i) { 1.1270 + list[i]->DoFireOnStateChange(aProgress, aRequest, aStateFlags, aStatus); 1.1271 + } 1.1272 +} 1.1273 + 1.1274 +void nsDocLoader::DoFireOnStateChange(nsIWebProgress * const aProgress, 1.1275 + nsIRequest * const aRequest, 1.1276 + int32_t &aStateFlags, 1.1277 + const nsresult aStatus) 1.1278 +{ 1.1279 + // 1.1280 + // Remove the STATE_IS_NETWORK bit if necessary. 1.1281 + // 1.1282 + // The rule is to remove this bit, if the notification has been passed 1.1283 + // up from a child WebProgress, and the current WebProgress is already 1.1284 + // active... 1.1285 + // 1.1286 + if (mIsLoadingDocument && 1.1287 + (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) && 1.1288 + (this != aProgress)) { 1.1289 + aStateFlags &= ~nsIWebProgressListener::STATE_IS_NETWORK; 1.1290 + } 1.1291 + 1.1292 + // Add the STATE_RESTORING bit if necessary. 1.1293 + if (mIsRestoringDocument) 1.1294 + aStateFlags |= nsIWebProgressListener::STATE_RESTORING; 1.1295 + 1.1296 +#if defined(DEBUG) 1.1297 + nsAutoCString buffer; 1.1298 + 1.1299 + GetURIStringFromRequest(aRequest, buffer); 1.1300 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.1301 + ("DocLoader:%p: Status (%s): code: %x\n", 1.1302 + this, buffer.get(), aStateFlags)); 1.1303 +#endif /* DEBUG */ 1.1304 + 1.1305 + NS_ASSERTION(aRequest, "Firing OnStateChange(...) notification with a NULL request!"); 1.1306 + 1.1307 + /* 1.1308 + * First notify any listeners of the new state info... 1.1309 + * 1.1310 + * Operate the elements from back to front so that if items get 1.1311 + * get removed from the list it won't affect our iteration 1.1312 + */ 1.1313 + nsCOMPtr<nsIWebProgressListener> listener; 1.1314 + int32_t count = mListenerInfoList.Count(); 1.1315 + int32_t notifyMask = (aStateFlags >> 16) & nsIWebProgress::NOTIFY_STATE_ALL; 1.1316 + 1.1317 + while (--count >= 0) { 1.1318 + nsListenerInfo *info; 1.1319 + 1.1320 + info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count)); 1.1321 + if (!info || !(info->mNotifyMask & notifyMask)) { 1.1322 + continue; 1.1323 + } 1.1324 + 1.1325 + listener = do_QueryReferent(info->mWeakListener); 1.1326 + if (!listener) { 1.1327 + // the listener went away. gracefully pull it out of the list. 1.1328 + mListenerInfoList.RemoveElementAt(count); 1.1329 + delete info; 1.1330 + continue; 1.1331 + } 1.1332 + 1.1333 + listener->OnStateChange(aProgress, aRequest, aStateFlags, aStatus); 1.1334 + } 1.1335 + 1.1336 + mListenerInfoList.Compact(); 1.1337 +} 1.1338 + 1.1339 + 1.1340 + 1.1341 +void 1.1342 +nsDocLoader::FireOnLocationChange(nsIWebProgress* aWebProgress, 1.1343 + nsIRequest* aRequest, 1.1344 + nsIURI *aUri, 1.1345 + uint32_t aFlags) 1.1346 +{ 1.1347 + /* 1.1348 + * First notify any listeners of the new state info... 1.1349 + * 1.1350 + * Operate the elements from back to front so that if items get 1.1351 + * get removed from the list it won't affect our iteration 1.1352 + */ 1.1353 + nsCOMPtr<nsIWebProgressListener> listener; 1.1354 + int32_t count = mListenerInfoList.Count(); 1.1355 + 1.1356 + while (--count >= 0) { 1.1357 + nsListenerInfo *info; 1.1358 + 1.1359 + info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count)); 1.1360 + if (!info || !(info->mNotifyMask & nsIWebProgress::NOTIFY_LOCATION)) { 1.1361 + continue; 1.1362 + } 1.1363 + 1.1364 + listener = do_QueryReferent(info->mWeakListener); 1.1365 + if (!listener) { 1.1366 + // the listener went away. gracefully pull it out of the list. 1.1367 + mListenerInfoList.RemoveElementAt(count); 1.1368 + delete info; 1.1369 + continue; 1.1370 + } 1.1371 + 1.1372 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, ("DocLoader [%p] calling %p->OnLocationChange", this, listener.get())); 1.1373 + listener->OnLocationChange(aWebProgress, aRequest, aUri, aFlags); 1.1374 + } 1.1375 + 1.1376 + mListenerInfoList.Compact(); 1.1377 + 1.1378 + // Pass the notification up to the parent... 1.1379 + if (mParent) { 1.1380 + mParent->FireOnLocationChange(aWebProgress, aRequest, aUri, aFlags); 1.1381 + } 1.1382 +} 1.1383 + 1.1384 +void 1.1385 +nsDocLoader::FireOnStatusChange(nsIWebProgress* aWebProgress, 1.1386 + nsIRequest* aRequest, 1.1387 + nsresult aStatus, 1.1388 + const char16_t* aMessage) 1.1389 +{ 1.1390 + /* 1.1391 + * First notify any listeners of the new state info... 1.1392 + * 1.1393 + * Operate the elements from back to front so that if items get 1.1394 + * get removed from the list it won't affect our iteration 1.1395 + */ 1.1396 + nsCOMPtr<nsIWebProgressListener> listener; 1.1397 + int32_t count = mListenerInfoList.Count(); 1.1398 + 1.1399 + while (--count >= 0) { 1.1400 + nsListenerInfo *info; 1.1401 + 1.1402 + info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count)); 1.1403 + if (!info || !(info->mNotifyMask & nsIWebProgress::NOTIFY_STATUS)) { 1.1404 + continue; 1.1405 + } 1.1406 + 1.1407 + listener = do_QueryReferent(info->mWeakListener); 1.1408 + if (!listener) { 1.1409 + // the listener went away. gracefully pull it out of the list. 1.1410 + mListenerInfoList.RemoveElementAt(count); 1.1411 + delete info; 1.1412 + continue; 1.1413 + } 1.1414 + 1.1415 + listener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage); 1.1416 + } 1.1417 + mListenerInfoList.Compact(); 1.1418 + 1.1419 + // Pass the notification up to the parent... 1.1420 + if (mParent) { 1.1421 + mParent->FireOnStatusChange(aWebProgress, aRequest, aStatus, aMessage); 1.1422 + } 1.1423 +} 1.1424 + 1.1425 +bool 1.1426 +nsDocLoader::RefreshAttempted(nsIWebProgress* aWebProgress, 1.1427 + nsIURI *aURI, 1.1428 + int32_t aDelay, 1.1429 + bool aSameURI) 1.1430 +{ 1.1431 + /* 1.1432 + * Returns true if the refresh may proceed, 1.1433 + * false if the refresh should be blocked. 1.1434 + * 1.1435 + * First notify any listeners of the refresh attempt... 1.1436 + * 1.1437 + * Iterate the elements from back to front so that if items 1.1438 + * get removed from the list it won't affect our iteration 1.1439 + */ 1.1440 + bool allowRefresh = true; 1.1441 + int32_t count = mListenerInfoList.Count(); 1.1442 + 1.1443 + while (--count >= 0) { 1.1444 + nsListenerInfo *info; 1.1445 + 1.1446 + info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count)); 1.1447 + if (!info || !(info->mNotifyMask & nsIWebProgress::NOTIFY_REFRESH)) { 1.1448 + continue; 1.1449 + } 1.1450 + 1.1451 + nsCOMPtr<nsIWebProgressListener> listener = 1.1452 + do_QueryReferent(info->mWeakListener); 1.1453 + if (!listener) { 1.1454 + // the listener went away. gracefully pull it out of the list. 1.1455 + mListenerInfoList.RemoveElementAt(count); 1.1456 + delete info; 1.1457 + continue; 1.1458 + } 1.1459 + 1.1460 + nsCOMPtr<nsIWebProgressListener2> listener2 = 1.1461 + do_QueryReferent(info->mWeakListener); 1.1462 + if (!listener2) 1.1463 + continue; 1.1464 + 1.1465 + bool listenerAllowedRefresh; 1.1466 + nsresult listenerRV = listener2->OnRefreshAttempted( 1.1467 + aWebProgress, aURI, aDelay, aSameURI, &listenerAllowedRefresh); 1.1468 + if (NS_FAILED(listenerRV)) 1.1469 + continue; 1.1470 + 1.1471 + allowRefresh = allowRefresh && listenerAllowedRefresh; 1.1472 + } 1.1473 + 1.1474 + mListenerInfoList.Compact(); 1.1475 + 1.1476 + // Pass the notification up to the parent... 1.1477 + if (mParent) { 1.1478 + allowRefresh = allowRefresh && 1.1479 + mParent->RefreshAttempted(aWebProgress, aURI, aDelay, aSameURI); 1.1480 + } 1.1481 + 1.1482 + return allowRefresh; 1.1483 +} 1.1484 + 1.1485 +nsListenerInfo * 1.1486 +nsDocLoader::GetListenerInfo(nsIWebProgressListener *aListener) 1.1487 +{ 1.1488 + int32_t i, count; 1.1489 + nsListenerInfo *info; 1.1490 + 1.1491 + nsCOMPtr<nsISupports> listener1 = do_QueryInterface(aListener); 1.1492 + count = mListenerInfoList.Count(); 1.1493 + for (i=0; i<count; i++) { 1.1494 + info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(i)); 1.1495 + 1.1496 + NS_ASSERTION(info, "There should NEVER be a null listener in the list"); 1.1497 + if (info) { 1.1498 + nsCOMPtr<nsISupports> listener2 = do_QueryReferent(info->mWeakListener); 1.1499 + if (listener1 == listener2) 1.1500 + return info; 1.1501 + } 1.1502 + } 1.1503 + return nullptr; 1.1504 +} 1.1505 + 1.1506 +nsresult nsDocLoader::AddRequestInfo(nsIRequest *aRequest) 1.1507 +{ 1.1508 + if (!PL_DHashTableOperate(&mRequestInfoHash, aRequest, PL_DHASH_ADD)) { 1.1509 + return NS_ERROR_OUT_OF_MEMORY; 1.1510 + } 1.1511 + 1.1512 + return NS_OK; 1.1513 +} 1.1514 + 1.1515 +void nsDocLoader::RemoveRequestInfo(nsIRequest *aRequest) 1.1516 +{ 1.1517 + PL_DHashTableOperate(&mRequestInfoHash, aRequest, PL_DHASH_REMOVE); 1.1518 +} 1.1519 + 1.1520 +nsDocLoader::nsRequestInfo* nsDocLoader::GetRequestInfo(nsIRequest* aRequest) 1.1521 +{ 1.1522 + nsRequestInfo* info = 1.1523 + static_cast<nsRequestInfo*> 1.1524 + (PL_DHashTableOperate(&mRequestInfoHash, aRequest, 1.1525 + PL_DHASH_LOOKUP)); 1.1526 + 1.1527 + if (PL_DHASH_ENTRY_IS_FREE(info)) { 1.1528 + // Nothing found in the hash, return null. 1.1529 + 1.1530 + return nullptr; 1.1531 + } 1.1532 + 1.1533 + // Return what we found in the hash... 1.1534 + 1.1535 + return info; 1.1536 +} 1.1537 + 1.1538 +// PLDHashTable enumeration callback that just removes every entry 1.1539 +// from the hash. 1.1540 +static PLDHashOperator 1.1541 +RemoveInfoCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, uint32_t number, 1.1542 + void *arg) 1.1543 +{ 1.1544 + return PL_DHASH_REMOVE; 1.1545 +} 1.1546 + 1.1547 +void nsDocLoader::ClearRequestInfoHash(void) 1.1548 +{ 1.1549 + if (!mRequestInfoHash.ops || !mRequestInfoHash.entryCount) { 1.1550 + // No hash, or the hash is empty, nothing to do here then... 1.1551 + 1.1552 + return; 1.1553 + } 1.1554 + 1.1555 + PL_DHashTableEnumerate(&mRequestInfoHash, RemoveInfoCallback, nullptr); 1.1556 +} 1.1557 + 1.1558 +// PLDHashTable enumeration callback that calculates the max progress. 1.1559 +PLDHashOperator 1.1560 +nsDocLoader::CalcMaxProgressCallback(PLDHashTable* table, PLDHashEntryHdr* hdr, 1.1561 + uint32_t number, void* arg) 1.1562 +{ 1.1563 + const nsRequestInfo* info = static_cast<const nsRequestInfo*>(hdr); 1.1564 + int64_t* max = static_cast<int64_t* >(arg); 1.1565 + 1.1566 + if (info->mMaxProgress < info->mCurrentProgress) { 1.1567 + *max = int64_t(-1); 1.1568 + 1.1569 + return PL_DHASH_STOP; 1.1570 + } 1.1571 + 1.1572 + *max += info->mMaxProgress; 1.1573 + 1.1574 + return PL_DHASH_NEXT; 1.1575 +} 1.1576 + 1.1577 +int64_t nsDocLoader::CalculateMaxProgress() 1.1578 +{ 1.1579 + int64_t max = mCompletedTotalProgress; 1.1580 + PL_DHashTableEnumerate(&mRequestInfoHash, CalcMaxProgressCallback, &max); 1.1581 + return max; 1.1582 +} 1.1583 + 1.1584 +NS_IMETHODIMP nsDocLoader::AsyncOnChannelRedirect(nsIChannel *aOldChannel, 1.1585 + nsIChannel *aNewChannel, 1.1586 + uint32_t aFlags, 1.1587 + nsIAsyncVerifyRedirectCallback *cb) 1.1588 +{ 1.1589 + if (aOldChannel) 1.1590 + { 1.1591 + nsLoadFlags loadFlags = 0; 1.1592 + int32_t stateFlags = nsIWebProgressListener::STATE_REDIRECTING | 1.1593 + nsIWebProgressListener::STATE_IS_REQUEST; 1.1594 + 1.1595 + aOldChannel->GetLoadFlags(&loadFlags); 1.1596 + // If the document channel is being redirected, then indicate that the 1.1597 + // document is being redirected in the notification... 1.1598 + if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) 1.1599 + { 1.1600 + stateFlags |= nsIWebProgressListener::STATE_IS_DOCUMENT; 1.1601 + 1.1602 +#if defined(DEBUG) 1.1603 + nsCOMPtr<nsIRequest> request(do_QueryInterface(aOldChannel)); 1.1604 + NS_ASSERTION(request == mDocumentRequest, "Wrong Document Channel"); 1.1605 +#endif /* DEBUG */ 1.1606 + } 1.1607 + 1.1608 + OnRedirectStateChange(aOldChannel, aNewChannel, aFlags, stateFlags); 1.1609 + FireOnStateChange(this, aOldChannel, stateFlags, NS_OK); 1.1610 + } 1.1611 + 1.1612 + cb->OnRedirectVerifyCallback(NS_OK); 1.1613 + return NS_OK; 1.1614 +} 1.1615 + 1.1616 +/* 1.1617 + * Implementation of nsISecurityEventSink method... 1.1618 + */ 1.1619 + 1.1620 +NS_IMETHODIMP nsDocLoader::OnSecurityChange(nsISupports * aContext, 1.1621 + uint32_t aState) 1.1622 +{ 1.1623 + // 1.1624 + // Fire progress notifications out to any registered nsIWebProgressListeners. 1.1625 + // 1.1626 + 1.1627 + nsCOMPtr<nsIRequest> request = do_QueryInterface(aContext); 1.1628 + nsIWebProgress* webProgress = static_cast<nsIWebProgress*>(this); 1.1629 + 1.1630 + /* 1.1631 + * First notify any listeners of the new state info... 1.1632 + * 1.1633 + * Operate the elements from back to front so that if items get 1.1634 + * get removed from the list it won't affect our iteration 1.1635 + */ 1.1636 + nsCOMPtr<nsIWebProgressListener> listener; 1.1637 + int32_t count = mListenerInfoList.Count(); 1.1638 + 1.1639 + while (--count >= 0) { 1.1640 + nsListenerInfo *info; 1.1641 + 1.1642 + info = static_cast<nsListenerInfo*>(mListenerInfoList.SafeElementAt(count)); 1.1643 + if (!info || !(info->mNotifyMask & nsIWebProgress::NOTIFY_SECURITY)) { 1.1644 + continue; 1.1645 + } 1.1646 + 1.1647 + listener = do_QueryReferent(info->mWeakListener); 1.1648 + if (!listener) { 1.1649 + // the listener went away. gracefully pull it out of the list. 1.1650 + mListenerInfoList.RemoveElementAt(count); 1.1651 + delete info; 1.1652 + continue; 1.1653 + } 1.1654 + 1.1655 + listener->OnSecurityChange(webProgress, request, aState); 1.1656 + } 1.1657 + 1.1658 + mListenerInfoList.Compact(); 1.1659 + 1.1660 + // Pass the notification up to the parent... 1.1661 + if (mParent) { 1.1662 + mParent->OnSecurityChange(aContext, aState); 1.1663 + } 1.1664 + return NS_OK; 1.1665 +} 1.1666 + 1.1667 +/* 1.1668 + * Implementation of nsISupportsPriority methods... 1.1669 + * 1.1670 + * The priority of the DocLoader _is_ the priority of its LoadGroup. 1.1671 + * 1.1672 + * XXX(darin): Once we start storing loadgroups in loadgroups, this code will 1.1673 + * go away. 1.1674 + */ 1.1675 + 1.1676 +NS_IMETHODIMP nsDocLoader::GetPriority(int32_t *aPriority) 1.1677 +{ 1.1678 + nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup); 1.1679 + if (p) 1.1680 + return p->GetPriority(aPriority); 1.1681 + 1.1682 + *aPriority = 0; 1.1683 + return NS_OK; 1.1684 +} 1.1685 + 1.1686 +NS_IMETHODIMP nsDocLoader::SetPriority(int32_t aPriority) 1.1687 +{ 1.1688 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.1689 + ("DocLoader:%p: SetPriority(%d) called\n", this, aPriority)); 1.1690 + 1.1691 + nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup); 1.1692 + if (p) 1.1693 + p->SetPriority(aPriority); 1.1694 + 1.1695 + NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList, nsDocLoader, 1.1696 + SetPriority, (aPriority)); 1.1697 + 1.1698 + return NS_OK; 1.1699 +} 1.1700 + 1.1701 +NS_IMETHODIMP nsDocLoader::AdjustPriority(int32_t aDelta) 1.1702 +{ 1.1703 + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 1.1704 + ("DocLoader:%p: AdjustPriority(%d) called\n", this, aDelta)); 1.1705 + 1.1706 + nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup); 1.1707 + if (p) 1.1708 + p->AdjustPriority(aDelta); 1.1709 + 1.1710 + NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList, nsDocLoader, 1.1711 + AdjustPriority, (aDelta)); 1.1712 + 1.1713 + return NS_OK; 1.1714 +} 1.1715 + 1.1716 + 1.1717 + 1.1718 + 1.1719 +#if 0 1.1720 +void nsDocLoader::DumpChannelInfo() 1.1721 +{ 1.1722 + nsChannelInfo *info; 1.1723 + int32_t i, count; 1.1724 + int32_t current=0, max=0; 1.1725 + 1.1726 + 1.1727 + printf("==== DocLoader=%x\n", this); 1.1728 + 1.1729 + count = mChannelInfoList.Count(); 1.1730 + for(i=0; i<count; i++) { 1.1731 + info = (nsChannelInfo *)mChannelInfoList.ElementAt(i); 1.1732 + 1.1733 +#if defined(DEBUG) 1.1734 + nsAutoCString buffer; 1.1735 + nsresult rv = NS_OK; 1.1736 + if (info->mURI) { 1.1737 + rv = info->mURI->GetSpec(buffer); 1.1738 + } 1.1739 + 1.1740 + printf(" [%d] current=%d max=%d [%s]\n", i, 1.1741 + info->mCurrentProgress, 1.1742 + info->mMaxProgress, buffer.get()); 1.1743 +#endif /* DEBUG */ 1.1744 + 1.1745 + current += info->mCurrentProgress; 1.1746 + if (max >= 0) { 1.1747 + if (info->mMaxProgress < info->mCurrentProgress) { 1.1748 + max = -1; 1.1749 + } else { 1.1750 + max += info->mMaxProgress; 1.1751 + } 1.1752 + } 1.1753 + } 1.1754 + 1.1755 + printf("\nCurrent=%d Total=%d\n====\n", current, max); 1.1756 +} 1.1757 +#endif /* 0 */