Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/nsDocLoader.h
Line
Count
Source (jump to first uncovered line)
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/. */
5
6
/*
7
*/
8
9
#ifndef nsDocLoader_h__
10
#define nsDocLoader_h__
11
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 "nsString.h"
21
#include "nsIChannel.h"
22
#include "nsIProgressEventSink.h"
23
#include "nsIInterfaceRequestor.h"
24
#include "nsIInterfaceRequestorUtils.h"
25
#include "nsIChannelEventSink.h"
26
#include "nsISecurityEventSink.h"
27
#include "nsISupportsPriority.h"
28
#include "nsCOMPtr.h"
29
#include "PLDHashTable.h"
30
#include "nsAutoPtr.h"
31
#include "nsCycleCollectionParticipant.h"
32
33
#include "mozilla/LinkedList.h"
34
35
/****************************************************************************
36
 * nsDocLoader implementation...
37
 ****************************************************************************/
38
39
#define NS_THIS_DOCLOADER_IMPL_CID                    \
40
 { /* b4ec8387-98aa-4c08-93b6-6d23069c06f2 */         \
41
     0xb4ec8387,                                      \
42
     0x98aa,                                          \
43
     0x4c08,                                          \
44
     {0x93, 0xb6, 0x6d, 0x23, 0x06, 0x9c, 0x06, 0xf2} \
45
 }
46
47
class nsDocLoader : public nsIDocumentLoader,
48
                    public nsIRequestObserver,
49
                    public nsSupportsWeakReference,
50
                    public nsIProgressEventSink,
51
                    public nsIWebProgress,
52
                    public nsIInterfaceRequestor,
53
                    public nsIChannelEventSink,
54
                    public nsISecurityEventSink,
55
                    public nsISupportsPriority
56
{
57
public:
58
    NS_DECLARE_STATIC_IID_ACCESSOR(NS_THIS_DOCLOADER_IMPL_CID)
59
60
    nsDocLoader();
61
62
    virtual MOZ_MUST_USE nsresult Init();
63
64
    static already_AddRefed<nsDocLoader> GetAsDocLoader(nsISupports* aSupports);
65
    // Needed to deal with ambiguous inheritance from nsISupports...
66
    static nsISupports* GetAsSupports(nsDocLoader* aDocLoader) {
67
        return static_cast<nsIDocumentLoader*>(aDocLoader);
68
    }
69
70
    // Add aDocLoader as a child to the docloader service.
71
    static MOZ_MUST_USE nsresult AddDocLoaderAsChildOfRoot(nsDocLoader* aDocLoader);
72
73
    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
74
    NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDocLoader, nsIDocumentLoader)
75
76
    NS_DECL_NSIDOCUMENTLOADER
77
78
    // nsIProgressEventSink
79
    NS_DECL_NSIPROGRESSEVENTSINK
80
81
    NS_DECL_NSISECURITYEVENTSINK
82
83
    // nsIRequestObserver methods: (for observing the load group)
84
    NS_DECL_NSIREQUESTOBSERVER
85
    NS_DECL_NSIWEBPROGRESS
86
87
    NS_DECL_NSIINTERFACEREQUESTOR
88
    NS_DECL_NSICHANNELEVENTSINK
89
    NS_DECL_NSISUPPORTSPRIORITY
90
91
    // Implementation specific methods...
92
93
    // Remove aChild from our childlist.  This nulls out the child's mParent
94
    // pointer.
95
    MOZ_MUST_USE nsresult RemoveChildLoader(nsDocLoader *aChild);
96
    // Add aChild to our child list.  This will set aChild's mParent pointer to
97
    // |this|.
98
    MOZ_MUST_USE nsresult AddChildLoader(nsDocLoader* aChild);
99
0
    nsDocLoader* GetParent() const { return mParent; }
100
101
    struct nsListenerInfo {
102
      nsListenerInfo(nsIWeakReference *aListener, unsigned long aNotifyMask)
103
        : mWeakListener(aListener),
104
          mNotifyMask(aNotifyMask)
105
      {
106
      }
107
108
      // Weak pointer for the nsIWebProgressListener...
109
      nsWeakPtr mWeakListener;
110
111
      // Mask indicating which notifications the listener wants to receive.
112
      unsigned long mNotifyMask;
113
    };
114
115
protected:
116
    virtual ~nsDocLoader();
117
118
    virtual MOZ_MUST_USE nsresult SetDocLoaderParent(nsDocLoader * aLoader);
119
120
    bool IsBusy();
121
122
    void Destroy();
123
    virtual void DestroyChildren();
124
125
    nsIDocumentLoader* ChildAt(int32_t i) {
126
        return mChildList.SafeElementAt(i, nullptr);
127
    }
128
129
    void FireOnProgressChange(nsDocLoader* aLoadInitiator,
130
                              nsIRequest *request,
131
                              int64_t aProgress,
132
                              int64_t aProgressMax,
133
                              int64_t aProgressDelta,
134
                              int64_t aTotalProgress,
135
                              int64_t aMaxTotalProgress);
136
137
    // This should be at least 2 long since we'll generally always
138
    // have the current page and the global docloader on the ancestor
139
    // list.  But to deal with frames it's better to make it a bit
140
    // longer, and it's always a stack temporary so there's no real
141
    // reason not to.
142
    typedef AutoTArray<RefPtr<nsDocLoader>, 8> WebProgressList;
143
    void GatherAncestorWebProgresses(WebProgressList& aList);
144
145
    void FireOnStateChange(nsIWebProgress *aProgress,
146
                           nsIRequest* request,
147
                           int32_t aStateFlags,
148
                           nsresult aStatus);
149
150
    // The guts of FireOnStateChange, but does not call itself on our ancestors.
151
    // The arguments that are const are const so that we can detect cases when
152
    // DoFireOnStateChange wants to propagate changes to the next web progress
153
    // at compile time.  The ones that are not, are references so that such
154
    // changes can be propagated.
155
    void DoFireOnStateChange(nsIWebProgress * const aProgress,
156
                             nsIRequest* const request,
157
                             int32_t &aStateFlags,
158
                             const nsresult aStatus);
159
160
    void FireOnStatusChange(nsIWebProgress *aWebProgress,
161
                            nsIRequest *aRequest,
162
                            nsresult aStatus,
163
                            const char16_t* aMessage);
164
165
    void FireOnLocationChange(nsIWebProgress* aWebProgress,
166
                              nsIRequest* aRequest,
167
                              nsIURI *aUri,
168
                              uint32_t aFlags);
169
170
    MOZ_MUST_USE bool RefreshAttempted(nsIWebProgress* aWebProgress,
171
                            nsIURI *aURI,
172
                            int32_t aDelay,
173
                            bool aSameURI);
174
175
    // this function is overridden by the docshell, it is provided so that we
176
    // can pass more information about redirect state (the normal OnStateChange
177
    // doesn't get the new channel).
178
    // @param aRedirectFlags The flags being sent to OnStateChange that
179
    //                       indicate the type of redirect.
180
    // @param aStateFlags    The channel flags normally sent to OnStateChange.
181
    virtual void OnRedirectStateChange(nsIChannel* aOldChannel,
182
                                       nsIChannel* aNewChannel,
183
                                       uint32_t aRedirectFlags,
184
                                       uint32_t aStateFlags) {}
185
186
    void doStartDocumentLoad();
187
    void doStartURLLoad(nsIRequest *request, int32_t aExtraFlags);
188
    void doStopURLLoad(nsIRequest *request, nsresult aStatus);
189
    void doStopDocumentLoad(nsIRequest *request, nsresult aStatus);
190
191
    // Inform a parent docloader that aChild is about to call its onload
192
    // handler.
193
    MOZ_MUST_USE bool ChildEnteringOnload(nsIDocumentLoader* aChild) {
194
        // It's ok if we're already in the list -- we'll just be in there twice
195
        // and then the RemoveObject calls from ChildDoneWithOnload will remove
196
        // us.
197
        return mChildrenInOnload.AppendObject(aChild);
198
    }
199
200
    // Inform a parent docloader that aChild is done calling its onload
201
    // handler.
202
    void ChildDoneWithOnload(nsIDocumentLoader* aChild) {
203
        mChildrenInOnload.RemoveObject(aChild);
204
        DocLoaderIsEmpty(true);
205
    }
206
207
protected:
208
    struct nsStatusInfo : public mozilla::LinkedListElement<nsStatusInfo>
209
    {
210
        nsString mStatusMessage;
211
        nsresult mStatusCode;
212
        // Weak mRequest is ok; we'll be told if it decides to go away.
213
        nsIRequest * const mRequest;
214
215
        explicit nsStatusInfo(nsIRequest* aRequest)
216
            : mStatusCode(NS_ERROR_NOT_INITIALIZED)
217
            , mRequest(aRequest)
218
        {
219
            MOZ_COUNT_CTOR(nsStatusInfo);
220
        }
221
        ~nsStatusInfo()
222
        {
223
            MOZ_COUNT_DTOR(nsStatusInfo);
224
        }
225
    };
226
227
    struct nsRequestInfo : public PLDHashEntryHdr
228
    {
229
        explicit nsRequestInfo(const void* key)
230
            : mKey(key), mCurrentProgress(0), mMaxProgress(0), mUploading(false)
231
            , mLastStatus(nullptr)
232
        {
233
            MOZ_COUNT_CTOR(nsRequestInfo);
234
        }
235
236
        ~nsRequestInfo()
237
        {
238
            MOZ_COUNT_DTOR(nsRequestInfo);
239
        }
240
241
0
        nsIRequest* Request() {
242
0
            return static_cast<nsIRequest*>(const_cast<void*>(mKey));
243
0
        }
244
245
        const void* mKey; // Must be first for the PLDHashTable stubs to work
246
        int64_t mCurrentProgress;
247
        int64_t mMaxProgress;
248
        bool mUploading;
249
250
        nsAutoPtr<nsStatusInfo> mLastStatus;
251
    };
252
253
    static void RequestInfoHashInitEntry(PLDHashEntryHdr* entry, const void* key);
254
    static void RequestInfoHashClearEntry(PLDHashTable* table, PLDHashEntryHdr* entry);
255
256
    // IMPORTANT: The ownership implicit in the following member
257
    // variables has been explicitly checked and set using nsCOMPtr
258
    // for owning pointers and raw COM interface pointers for weak
259
    // (ie, non owning) references. If you add any members to this
260
    // class, please make the ownership explicit (pinkerton, scc).
261
262
    nsCOMPtr<nsIRequest>       mDocumentRequest;       // [OWNER] ???compare with document
263
264
    nsDocLoader*               mParent;                // [WEAK]
265
266
    typedef nsAutoTObserverArray<nsListenerInfo, 8> ListenerArray;
267
    ListenerArray              mListenerInfoList;
268
269
    nsCOMPtr<nsILoadGroup>        mLoadGroup;
270
    // We hold weak refs to all our kids
271
    nsTObserverArray<nsDocLoader*> mChildList;
272
273
    // The following member variables are related to the new nsIWebProgress
274
    // feedback interfaces that travis cooked up.
275
    int32_t mProgressStateFlags;
276
277
    int64_t mCurrentSelfProgress;
278
    int64_t mMaxSelfProgress;
279
280
    int64_t mCurrentTotalProgress;
281
    int64_t mMaxTotalProgress;
282
283
    PLDHashTable mRequestInfoHash;
284
    int64_t mCompletedTotalProgress;
285
286
    mozilla::LinkedList<nsStatusInfo> mStatusInfoList;
287
288
    /*
289
     * This flag indicates that the loader is loading a document.  It is set
290
     * from the call to LoadDocument(...) until the OnConnectionsComplete(...)
291
     * notification is fired...
292
     */
293
    bool mIsLoadingDocument;
294
295
    /* Flag to indicate that we're in the process of restoring a document. */
296
    bool mIsRestoringDocument;
297
298
    /* Flag to indicate that we're in the process of flushing layout
299
       under DocLoaderIsEmpty() and should not do another flush. */
300
    bool mDontFlushLayout;
301
302
    /* Flag to indicate whether we should consider ourselves as currently
303
       flushing layout for the purposes of IsBusy. For example, if Stop has
304
       been called then IsBusy should return false even if we are still
305
       flushing. */
306
    bool mIsFlushingLayout;
307
308
private:
309
    static const PLDHashTableOps sRequestInfoHashOps;
310
311
    // A list of kids that are in the middle of their onload calls and will let
312
    // us know once they're done.  We don't want to fire onload for "normal"
313
    // DocLoaderIsEmpty calls (those coming from requests finishing in our
314
    // loadgroup) unless this is empty.
315
    nsCOMArray<nsIDocumentLoader> mChildrenInOnload;
316
317
    // DocLoaderIsEmpty should be called whenever the docloader may be empty.
318
    // This method is idempotent and does nothing if the docloader is not in
319
    // fact empty.  This method _does_ make sure that layout is flushed if our
320
    // loadgroup has no active requests before checking for "real" emptiness if
321
    // aFlushLayout is true.
322
    void DocLoaderIsEmpty(bool aFlushLayout);
323
324
    int64_t GetMaxTotalProgress();
325
326
    nsresult AddRequestInfo(nsIRequest* aRequest);
327
    void RemoveRequestInfo(nsIRequest* aRequest);
328
    nsRequestInfo *GetRequestInfo(nsIRequest* aRequest) const;
329
    void ClearRequestInfoHash();
330
    int64_t CalculateMaxProgress();
331
///    void DumpChannelInfo(void);
332
333
    // used to clear our internal progress state between loads...
334
    void ClearInternalProgress();
335
};
336
337
NS_DEFINE_STATIC_IID_ACCESSOR(nsDocLoader, NS_THIS_DOCLOADER_IMPL_CID)
338
339
#endif /* nsDocLoader_h__ */