Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 /*
7 */
9 #ifndef nsDocLoader_h__
10 #define nsDocLoader_h__
12 #include "nsIDocumentLoader.h"
13 #include "nsIWebProgress.h"
14 #include "nsIWebProgressListener.h"
15 #include "nsIRequestObserver.h"
16 #include "nsWeakReference.h"
17 #include "nsILoadGroup.h"
18 #include "nsCOMArray.h"
19 #include "nsTObserverArray.h"
20 #include "nsVoidArray.h"
21 #include "nsString.h"
22 #include "nsIChannel.h"
23 #include "nsIProgressEventSink.h"
24 #include "nsIInterfaceRequestor.h"
25 #include "nsIInterfaceRequestorUtils.h"
26 #include "nsIChannelEventSink.h"
27 #include "nsISecurityEventSink.h"
28 #include "nsISupportsPriority.h"
29 #include "nsCOMPtr.h"
30 #include "pldhash.h"
31 #include "nsAutoPtr.h"
33 #include "mozilla/LinkedList.h"
35 struct nsListenerInfo;
37 /****************************************************************************
38 * nsDocLoader implementation...
39 ****************************************************************************/
41 #define NS_THIS_DOCLOADER_IMPL_CID \
42 { /* b4ec8387-98aa-4c08-93b6-6d23069c06f2 */ \
43 0xb4ec8387, \
44 0x98aa, \
45 0x4c08, \
46 {0x93, 0xb6, 0x6d, 0x23, 0x06, 0x9c, 0x06, 0xf2} \
47 }
49 class nsDocLoader : public nsIDocumentLoader,
50 public nsIRequestObserver,
51 public nsSupportsWeakReference,
52 public nsIProgressEventSink,
53 public nsIWebProgress,
54 public nsIInterfaceRequestor,
55 public nsIChannelEventSink,
56 public nsISecurityEventSink,
57 public nsISupportsPriority
58 {
59 public:
60 NS_DECLARE_STATIC_IID_ACCESSOR(NS_THIS_DOCLOADER_IMPL_CID)
62 nsDocLoader();
64 virtual nsresult Init();
66 static already_AddRefed<nsDocLoader> GetAsDocLoader(nsISupports* aSupports);
67 // Needed to deal with ambiguous inheritance from nsISupports...
68 static nsISupports* GetAsSupports(nsDocLoader* aDocLoader) {
69 return static_cast<nsIDocumentLoader*>(aDocLoader);
70 }
72 // Add aDocLoader as a child to the docloader service.
73 static nsresult AddDocLoaderAsChildOfRoot(nsDocLoader* aDocLoader);
75 NS_DECL_ISUPPORTS
76 NS_DECL_NSIDOCUMENTLOADER
78 // nsIProgressEventSink
79 NS_DECL_NSIPROGRESSEVENTSINK
81 NS_DECL_NSISECURITYEVENTSINK
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
91 // Implementation specific methods...
93 // Remove aChild from our childlist. This nulls out the child's mParent
94 // pointer.
95 nsresult RemoveChildLoader(nsDocLoader *aChild);
96 // Add aChild to our child list. This will set aChild's mParent pointer to
97 // |this|.
98 nsresult AddChildLoader(nsDocLoader* aChild);
99 nsDocLoader* GetParent() const { return mParent; }
101 protected:
102 virtual ~nsDocLoader();
104 virtual nsresult SetDocLoaderParent(nsDocLoader * aLoader);
106 bool IsBusy();
108 void Destroy();
109 virtual void DestroyChildren();
111 nsIDocumentLoader* ChildAt(int32_t i) {
112 return mChildList.SafeElementAt(i, nullptr);
113 }
115 void FireOnProgressChange(nsDocLoader* aLoadInitiator,
116 nsIRequest *request,
117 int64_t aProgress,
118 int64_t aProgressMax,
119 int64_t aProgressDelta,
120 int64_t aTotalProgress,
121 int64_t aMaxTotalProgress);
123 // This should be at least 2 long since we'll generally always
124 // have the current page and the global docloader on the ancestor
125 // list. But to deal with frames it's better to make it a bit
126 // longer, and it's always a stack temporary so there's no real
127 // reason not to.
128 typedef nsAutoTArray<nsRefPtr<nsDocLoader>, 8> WebProgressList;
129 void GatherAncestorWebProgresses(WebProgressList& aList);
131 void FireOnStateChange(nsIWebProgress *aProgress,
132 nsIRequest* request,
133 int32_t aStateFlags,
134 nsresult aStatus);
136 // The guts of FireOnStateChange, but does not call itself on our ancestors.
137 // The arguments that are const are const so that we can detect cases when
138 // DoFireOnStateChange wants to propagate changes to the next web progress
139 // at compile time. The ones that are not, are references so that such
140 // changes can be propagated.
141 void DoFireOnStateChange(nsIWebProgress * const aProgress,
142 nsIRequest* const request,
143 int32_t &aStateFlags,
144 const nsresult aStatus);
146 void FireOnStatusChange(nsIWebProgress *aWebProgress,
147 nsIRequest *aRequest,
148 nsresult aStatus,
149 const char16_t* aMessage);
151 void FireOnLocationChange(nsIWebProgress* aWebProgress,
152 nsIRequest* aRequest,
153 nsIURI *aUri,
154 uint32_t aFlags);
156 bool RefreshAttempted(nsIWebProgress* aWebProgress,
157 nsIURI *aURI,
158 int32_t aDelay,
159 bool aSameURI);
161 // this function is overridden by the docshell, it is provided so that we
162 // can pass more information about redirect state (the normal OnStateChange
163 // doesn't get the new channel).
164 // @param aRedirectFlags The flags being sent to OnStateChange that
165 // indicate the type of redirect.
166 // @param aStateFlags The channel flags normally sent to OnStateChange.
167 virtual void OnRedirectStateChange(nsIChannel* aOldChannel,
168 nsIChannel* aNewChannel,
169 uint32_t aRedirectFlags,
170 uint32_t aStateFlags) {}
172 void doStartDocumentLoad();
173 void doStartURLLoad(nsIRequest *request);
174 void doStopURLLoad(nsIRequest *request, nsresult aStatus);
175 void doStopDocumentLoad(nsIRequest *request, nsresult aStatus);
177 // Inform a parent docloader that aChild is about to call its onload
178 // handler.
179 bool ChildEnteringOnload(nsIDocumentLoader* aChild) {
180 // It's ok if we're already in the list -- we'll just be in there twice
181 // and then the RemoveObject calls from ChildDoneWithOnload will remove
182 // us.
183 return mChildrenInOnload.AppendObject(aChild);
184 }
186 // Inform a parent docloader that aChild is done calling its onload
187 // handler.
188 void ChildDoneWithOnload(nsIDocumentLoader* aChild) {
189 mChildrenInOnload.RemoveObject(aChild);
190 DocLoaderIsEmpty(true);
191 }
193 protected:
194 struct nsStatusInfo : public mozilla::LinkedListElement<nsStatusInfo>
195 {
196 nsString mStatusMessage;
197 nsresult mStatusCode;
198 // Weak mRequest is ok; we'll be told if it decides to go away.
199 nsIRequest * const mRequest;
201 nsStatusInfo(nsIRequest* aRequest) :
202 mRequest(aRequest)
203 {
204 MOZ_COUNT_CTOR(nsStatusInfo);
205 }
206 ~nsStatusInfo()
207 {
208 MOZ_COUNT_DTOR(nsStatusInfo);
209 }
210 };
212 struct nsRequestInfo : public PLDHashEntryHdr
213 {
214 nsRequestInfo(const void* key)
215 : mKey(key), mCurrentProgress(0), mMaxProgress(0), mUploading(false)
216 , mLastStatus(nullptr)
217 {
218 MOZ_COUNT_CTOR(nsRequestInfo);
219 }
221 ~nsRequestInfo()
222 {
223 MOZ_COUNT_DTOR(nsRequestInfo);
224 }
226 nsIRequest* Request() {
227 return static_cast<nsIRequest*>(const_cast<void*>(mKey));
228 }
230 const void* mKey; // Must be first for the pldhash stubs to work
231 int64_t mCurrentProgress;
232 int64_t mMaxProgress;
233 bool mUploading;
235 nsAutoPtr<nsStatusInfo> mLastStatus;
236 };
238 static bool RequestInfoHashInitEntry(PLDHashTable* table, PLDHashEntryHdr* entry,
239 const void* key);
240 static void RequestInfoHashClearEntry(PLDHashTable* table, PLDHashEntryHdr* entry);
242 // IMPORTANT: The ownership implicit in the following member
243 // variables has been explicitly checked and set using nsCOMPtr
244 // for owning pointers and raw COM interface pointers for weak
245 // (ie, non owning) references. If you add any members to this
246 // class, please make the ownership explicit (pinkerton, scc).
248 nsCOMPtr<nsIRequest> mDocumentRequest; // [OWNER] ???compare with document
250 nsDocLoader* mParent; // [WEAK]
252 nsVoidArray mListenerInfoList;
254 nsCOMPtr<nsILoadGroup> mLoadGroup;
255 // We hold weak refs to all our kids
256 nsTObserverArray<nsDocLoader*> mChildList;
258 // The following member variables are related to the new nsIWebProgress
259 // feedback interfaces that travis cooked up.
260 int32_t mProgressStateFlags;
262 int64_t mCurrentSelfProgress;
263 int64_t mMaxSelfProgress;
265 int64_t mCurrentTotalProgress;
266 int64_t mMaxTotalProgress;
268 PLDHashTable mRequestInfoHash;
269 int64_t mCompletedTotalProgress;
271 mozilla::LinkedList<nsStatusInfo> mStatusInfoList;
273 /*
274 * This flag indicates that the loader is loading a document. It is set
275 * from the call to LoadDocument(...) until the OnConnectionsComplete(...)
276 * notification is fired...
277 */
278 bool mIsLoadingDocument;
280 /* Flag to indicate that we're in the process of restoring a document. */
281 bool mIsRestoringDocument;
283 /* Flag to indicate that we're in the process of flushing layout
284 under DocLoaderIsEmpty() and should not do another flush. */
285 bool mDontFlushLayout;
287 /* Flag to indicate whether we should consider ourselves as currently
288 flushing layout for the purposes of IsBusy. For example, if Stop has
289 been called then IsBusy should return false even if we are still
290 flushing. */
291 bool mIsFlushingLayout;
293 private:
294 // A list of kids that are in the middle of their onload calls and will let
295 // us know once they're done. We don't want to fire onload for "normal"
296 // DocLoaderIsEmpty calls (those coming from requests finishing in our
297 // loadgroup) unless this is empty.
298 nsCOMArray<nsIDocumentLoader> mChildrenInOnload;
300 // DocLoaderIsEmpty should be called whenever the docloader may be empty.
301 // This method is idempotent and does nothing if the docloader is not in
302 // fact empty. This method _does_ make sure that layout is flushed if our
303 // loadgroup has no active requests before checking for "real" emptiness if
304 // aFlushLayout is true.
305 void DocLoaderIsEmpty(bool aFlushLayout);
307 nsListenerInfo *GetListenerInfo(nsIWebProgressListener* aListener);
309 int64_t GetMaxTotalProgress();
311 nsresult AddRequestInfo(nsIRequest* aRequest);
312 void RemoveRequestInfo(nsIRequest* aRequest);
313 nsRequestInfo *GetRequestInfo(nsIRequest* aRequest);
314 void ClearRequestInfoHash();
315 int64_t CalculateMaxProgress();
316 static PLDHashOperator CalcMaxProgressCallback(PLDHashTable* table,
317 PLDHashEntryHdr* hdr,
318 uint32_t number, void* arg);
319 /// void DumpChannelInfo(void);
321 // used to clear our internal progress state between loads...
322 void ClearInternalProgress();
323 };
325 NS_DEFINE_STATIC_IID_ACCESSOR(nsDocLoader, NS_THIS_DOCLOADER_IMPL_CID)
327 #endif /* nsDocLoader_h__ */