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