Bug 1845017 - Disable the TestPHCExhaustion test r=glandium
[gecko.git] / uriloader / base / nsDocLoader.h
blobe828cb8a116eb3627a974e256b8c37301db3d9f7
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/. */
6 #ifndef nsDocLoader_h__
7 #define nsDocLoader_h__
9 #include "nsIDocumentLoader.h"
10 #include "nsIWebProgress.h"
11 #include "nsIWebProgressListener.h"
12 #include "nsIRequestObserver.h"
13 #include "nsWeakReference.h"
14 #include "nsILoadGroup.h"
15 #include "nsCOMArray.h"
16 #include "nsTObserverArray.h"
17 #include "nsString.h"
18 #include "nsIChannel.h"
19 #include "nsIProgressEventSink.h"
20 #include "nsIInterfaceRequestor.h"
21 #include "nsIInterfaceRequestorUtils.h"
22 #include "nsIChannelEventSink.h"
23 #include "nsISupportsPriority.h"
24 #include "nsCOMPtr.h"
25 #include "PLDHashTable.h"
26 #include "nsCycleCollectionParticipant.h"
28 #include "mozilla/LinkedList.h"
29 #include "mozilla/UniquePtr.h"
31 namespace mozilla {
32 namespace dom {
33 class BrowsingContext;
34 } // namespace dom
35 } // namespace mozilla
37 /****************************************************************************
38 * nsDocLoader implementation...
39 ****************************************************************************/
41 #define NS_THIS_DOCLOADER_IMPL_CID \
42 { /* b4ec8387-98aa-4c08-93b6-6d23069c06f2 */ \
43 0xb4ec8387, 0x98aa, 0x4c08, { \
44 0x93, 0xb6, 0x6d, 0x23, 0x06, 0x9c, 0x06, 0xf2 \
45 } \
48 class nsDocLoader : public nsIDocumentLoader,
49 public nsIRequestObserver,
50 public nsSupportsWeakReference,
51 public nsIProgressEventSink,
52 public nsIWebProgress,
53 public nsIInterfaceRequestor,
54 public nsIChannelEventSink,
55 public nsISupportsPriority {
56 public:
57 NS_DECLARE_STATIC_IID_ACCESSOR(NS_THIS_DOCLOADER_IMPL_CID)
59 nsDocLoader() : nsDocLoader(false) {}
61 [[nodiscard]] virtual nsresult Init();
62 [[nodiscard]] nsresult InitWithBrowsingContext(
63 mozilla::dom::BrowsingContext* aBrowsingContext);
65 static already_AddRefed<nsDocLoader> GetAsDocLoader(nsISupports* aSupports);
66 // Needed to deal with ambiguous inheritance from nsISupports...
67 static nsISupports* GetAsSupports(nsDocLoader* aDocLoader) {
68 return static_cast<nsIDocumentLoader*>(aDocLoader);
71 // Add aDocLoader as a child to the docloader service.
72 [[nodiscard]] static nsresult AddDocLoaderAsChildOfRoot(
73 nsDocLoader* aDocLoader);
75 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
76 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDocLoader, nsIDocumentLoader)
78 NS_DECL_NSIDOCUMENTLOADER
80 // nsIProgressEventSink
81 NS_DECL_NSIPROGRESSEVENTSINK
83 // nsIRequestObserver methods: (for observing the load group)
84 NS_DECL_NSIREQUESTOBSERVER
85 NS_DECL_NSIWEBPROGRESS
87 NS_DECL_NSIINTERFACEREQUESTOR
88 NS_DECL_NSICHANNELEVENTSINK
89 NS_DECL_NSISUPPORTSPRIORITY; // semicolon for clang-format bug 1629756
91 // Implementation specific methods...
93 // Remove aChild from our childlist. This nulls out the child's mParent
94 // pointer.
95 [[nodiscard]] nsresult RemoveChildLoader(nsDocLoader* aChild);
97 // Add aChild to our child list. This will set aChild's mParent pointer to
98 // |this|.
99 [[nodiscard]] nsresult AddChildLoader(nsDocLoader* aChild);
100 nsDocLoader* GetParent() const { return mParent; }
102 struct nsListenerInfo {
103 nsListenerInfo(nsIWeakReference* aListener, unsigned long aNotifyMask)
104 : mWeakListener(aListener), mNotifyMask(aNotifyMask) {}
106 // Weak pointer for the nsIWebProgressListener...
107 nsWeakPtr mWeakListener;
109 // Mask indicating which notifications the listener wants to receive.
110 unsigned long mNotifyMask;
114 * Fired when a security change occurs due to page transitions,
115 * or end document load. This interface should be called by
116 * a security package (eg Netscape Personal Security Manager)
117 * to notify nsIWebProgressListeners that security state has
118 * changed. State flags are in nsIWebProgressListener.idl
120 void OnSecurityChange(nsISupports* aContext, uint32_t aState);
122 void SetDocumentOpenedButNotLoaded() { mDocumentOpenedButNotLoaded = true; }
124 bool TreatAsBackgroundLoad();
126 void SetFakeOnLoadDispatched() { mHasFakeOnLoadDispatched = true; };
128 bool HasFakeOnLoadDispatched() { return mHasFakeOnLoadDispatched; };
130 void ResetToFirstLoad() {
131 mHasFakeOnLoadDispatched = false;
132 mIsReadyToHandlePostMessage = false;
133 mTreatAsBackgroundLoad = false;
136 uint32_t ChildCount() const { return mChildList.Length(); }
138 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
139 MOZ_CAN_RUN_SCRIPT_BOUNDARY void OOPChildrenLoadingIsEmpty() {
140 DocLoaderIsEmpty(true);
143 protected:
144 explicit nsDocLoader(bool aNotifyAboutBackgroundRequests);
145 virtual ~nsDocLoader();
147 [[nodiscard]] virtual nsresult SetDocLoaderParent(nsDocLoader* aLoader);
149 bool IsBusy();
151 void SetBackgroundLoadIframe();
153 void Destroy();
154 virtual void DestroyChildren();
156 nsIDocumentLoader* ChildAt(int32_t i) {
157 return mChildList.SafeElementAt(i, nullptr);
160 void FireOnProgressChange(nsDocLoader* aLoadInitiator, nsIRequest* request,
161 int64_t aProgress, int64_t aProgressMax,
162 int64_t aProgressDelta, int64_t aTotalProgress,
163 int64_t aMaxTotalProgress);
165 // This should be at least 2 long since we'll generally always
166 // have the current page and the global docloader on the ancestor
167 // list. But to deal with frames it's better to make it a bit
168 // longer, and it's always a stack temporary so there's no real
169 // reason not to.
170 typedef AutoTArray<RefPtr<nsDocLoader>, 8> WebProgressList;
171 void GatherAncestorWebProgresses(WebProgressList& aList);
173 void FireOnStateChange(nsIWebProgress* aProgress, nsIRequest* request,
174 int32_t aStateFlags, nsresult aStatus);
176 // The guts of FireOnStateChange, but does not call itself on our ancestors.
177 // The arguments that are const are const so that we can detect cases when
178 // DoFireOnStateChange wants to propagate changes to the next web progress
179 // at compile time. The ones that are not, are references so that such
180 // changes can be propagated.
181 void DoFireOnStateChange(nsIWebProgress* const aProgress,
182 nsIRequest* const request, int32_t& aStateFlags,
183 const nsresult aStatus);
185 void FireOnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
186 nsresult aStatus, const char16_t* aMessage);
188 void FireOnLocationChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
189 nsIURI* aUri, uint32_t aFlags);
191 [[nodiscard]] bool RefreshAttempted(nsIWebProgress* aWebProgress,
192 nsIURI* aURI, uint32_t aDelay,
193 bool aSameURI);
195 // this function is overridden by the docshell, it is provided so that we
196 // can pass more information about redirect state (the normal OnStateChange
197 // doesn't get the new channel).
198 // @param aRedirectFlags The flags being sent to OnStateChange that
199 // indicate the type of redirect.
200 // @param aStateFlags The channel flags normally sent to OnStateChange.
201 virtual void OnRedirectStateChange(nsIChannel* aOldChannel,
202 nsIChannel* aNewChannel,
203 uint32_t aRedirectFlags,
204 uint32_t aStateFlags) {}
206 void doStartDocumentLoad();
207 void doStartURLLoad(nsIRequest* request, int32_t aExtraFlags);
208 void doStopURLLoad(nsIRequest* request, nsresult aStatus);
209 void doStopDocumentLoad(nsIRequest* request, nsresult aStatus);
211 void NotifyDoneWithOnload(nsDocLoader* aParent);
213 // Inform a parent docloader that aChild is about to call its onload
214 // handler.
215 [[nodiscard]] bool ChildEnteringOnload(nsIDocumentLoader* aChild) {
216 // It's ok if we're already in the list -- we'll just be in there twice
217 // and then the RemoveObject calls from ChildDoneWithOnload will remove
218 // us.
219 return mChildrenInOnload.AppendObject(aChild);
222 // Inform a parent docloader that aChild is done calling its onload
223 // handler.
224 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
225 MOZ_CAN_RUN_SCRIPT_BOUNDARY void ChildDoneWithOnload(
226 nsIDocumentLoader* aChild) {
227 mChildrenInOnload.RemoveObject(aChild);
228 DocLoaderIsEmpty(true);
231 // DocLoaderIsEmpty should be called whenever the docloader may be empty.
232 // This method is idempotent and does nothing if the docloader is not in
233 // fact empty. This method _does_ make sure that layout is flushed if our
234 // loadgroup has no active requests before checking for "real" emptiness if
235 // aFlushLayout is true.
236 // @param aOverrideStatus An optional status to use when notifying listeners
237 // of the completed load, instead of using the load group's status.
238 MOZ_CAN_RUN_SCRIPT void DocLoaderIsEmpty(
239 bool aFlushLayout,
240 const mozilla::Maybe<nsresult>& aOverrideStatus = mozilla::Nothing());
242 protected:
243 struct nsStatusInfo : public mozilla::LinkedListElement<nsStatusInfo> {
244 nsString mStatusMessage;
245 nsresult mStatusCode;
246 // Weak mRequest is ok; we'll be told if it decides to go away.
247 nsIRequest* const mRequest;
249 explicit nsStatusInfo(nsIRequest* aRequest)
250 : mStatusCode(NS_ERROR_NOT_INITIALIZED), mRequest(aRequest) {
251 MOZ_COUNT_CTOR(nsStatusInfo);
253 MOZ_COUNTED_DTOR(nsStatusInfo)
256 struct nsRequestInfo : public PLDHashEntryHdr {
257 explicit nsRequestInfo(const void* key)
258 : mKey(key),
259 mCurrentProgress(0),
260 mMaxProgress(0),
261 mUploading(false),
262 mLastStatus(nullptr) {
263 MOZ_COUNT_CTOR(nsRequestInfo);
266 MOZ_COUNTED_DTOR(nsRequestInfo)
268 nsIRequest* Request() {
269 return static_cast<nsIRequest*>(const_cast<void*>(mKey));
272 const void* mKey; // Must be first for the PLDHashTable stubs to work
273 int64_t mCurrentProgress;
274 int64_t mMaxProgress;
275 bool mUploading;
277 mozilla::UniquePtr<nsStatusInfo> mLastStatus;
280 static void RequestInfoHashInitEntry(PLDHashEntryHdr* entry, const void* key);
281 static void RequestInfoHashClearEntry(PLDHashTable* table,
282 PLDHashEntryHdr* entry);
284 // IMPORTANT: The ownership implicit in the following member
285 // variables has been explicitly checked and set using nsCOMPtr
286 // for owning pointers and raw COM interface pointers for weak
287 // (ie, non owning) references. If you add any members to this
288 // class, please make the ownership explicit (pinkerton, scc).
290 nsCOMPtr<nsIRequest> mDocumentRequest; // [OWNER] ???compare with document
292 nsDocLoader* mParent; // [WEAK]
294 typedef nsAutoTObserverArray<nsListenerInfo, 8> ListenerArray;
295 ListenerArray mListenerInfoList;
297 nsCOMPtr<nsILoadGroup> mLoadGroup;
298 // We hold weak refs to all our kids
299 nsTObserverArray<nsDocLoader*> mChildList;
301 // The following member variables are related to the new nsIWebProgress
302 // feedback interfaces that travis cooked up.
303 int32_t mProgressStateFlags;
305 int64_t mCurrentSelfProgress;
306 int64_t mMaxSelfProgress;
308 int64_t mCurrentTotalProgress;
309 int64_t mMaxTotalProgress;
311 PLDHashTable mRequestInfoHash;
312 int64_t mCompletedTotalProgress;
314 mozilla::LinkedList<nsStatusInfo> mStatusInfoList;
317 * This flag indicates that the loader is loading a document. It is set
318 * from the call to LoadDocument(...) until the OnConnectionsComplete(...)
319 * notification is fired...
321 bool mIsLoadingDocument;
323 /* Flag to indicate that we're in the process of restoring a document. */
324 bool mIsRestoringDocument;
326 /* Flag to indicate that we're in the process of flushing layout
327 under DocLoaderIsEmpty() and should not do another flush. */
328 bool mDontFlushLayout;
330 /* Flag to indicate whether we should consider ourselves as currently
331 flushing layout for the purposes of IsBusy. For example, if Stop has
332 been called then IsBusy should return false even if we are still
333 flushing. */
334 bool mIsFlushingLayout;
336 bool mTreatAsBackgroundLoad;
338 private:
339 bool mHasFakeOnLoadDispatched;
341 bool mIsReadyToHandlePostMessage;
343 * This flag indicates that the loader is waiting for completion of
344 * a document.open-triggered "document load". This is set when
345 * document.open() happens and sets up a new parser and cleared out
346 * when we go to fire our load event or end up with a new document
347 * channel.
349 bool mDocumentOpenedButNotLoaded;
351 bool mNotifyAboutBackgroundRequests;
353 static const PLDHashTableOps sRequestInfoHashOps;
355 // A list of kids that are in the middle of their onload calls and will let
356 // us know once they're done. We don't want to fire onload for "normal"
357 // DocLoaderIsEmpty calls (those coming from requests finishing in our
358 // loadgroup) unless this is empty.
359 nsCOMArray<nsIDocumentLoader> mChildrenInOnload;
361 int64_t GetMaxTotalProgress();
363 nsresult AddRequestInfo(nsIRequest* aRequest);
364 void RemoveRequestInfo(nsIRequest* aRequest);
365 nsRequestInfo* GetRequestInfo(nsIRequest* aRequest) const;
366 void ClearRequestInfoHash();
367 int64_t CalculateMaxProgress();
368 /// void DumpChannelInfo(void);
370 // used to clear our internal progress state between loads...
371 void ClearInternalProgress();
374 * Used to test whether we might need to fire a load event. This
375 * can happen when we have a document load going on, or when we've
376 * had document.open() called and haven't fired the corresponding
377 * load event yet.
379 bool IsBlockingLoadEvent() const {
380 return mIsLoadingDocument || mDocumentOpenedButNotLoaded;
384 NS_DEFINE_STATIC_IID_ACCESSOR(nsDocLoader, NS_THIS_DOCLOADER_IMPL_CID)
386 static inline nsISupports* ToSupports(nsDocLoader* aDocLoader) {
387 return static_cast<nsIDocumentLoader*>(aDocLoader);
390 #endif /* nsDocLoader_h__ */