Bug 1829125 - Align the PHC area to the jemalloc chunk size r=glandium
[gecko.git] / uriloader / preload / PreloaderBase.h
blob2ecb37a1fdd547cd77ab77a8945b6bbae7a0cc93
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef PreloaderBase_h__
6 #define PreloaderBase_h__
8 #include "mozilla/Maybe.h"
9 #include "mozilla/PreloadHashKey.h"
10 #include "mozilla/WeakPtr.h"
11 #include "nsCOMPtr.h"
12 #include "nsISupports.h"
13 #include "nsITimer.h"
14 #include "nsIURI.h"
15 #include "nsIWeakReferenceUtils.h"
16 #include "nsTArray.h"
18 class nsIChannel;
19 class nsINode;
20 class nsIRequest;
21 class nsIStreamListener;
23 namespace mozilla {
25 namespace dom {
27 class Document;
29 } // namespace dom
31 /**
32 * A half-abstract base class that resource loaders' respective
33 * channel-listening classes should derive from. Provides a unified API to
34 * register the load or preload in a document scoped service, links <link
35 * rel="preload"> DOM nodes with the load progress and provides API to possibly
36 * consume the data by later, dynamically discovered consumers.
38 * This class is designed to be used only on the main thread.
40 class PreloaderBase : public SupportsWeakPtr, public nsISupports {
41 public:
42 PreloaderBase() = default;
44 // Called by resource loaders to register this preload in the document's
45 // preload service to provide coalescing, and access to the preload when it
46 // should be used for an actual load.
47 void NotifyOpen(const PreloadHashKey& aKey, dom::Document* aDocument,
48 bool aIsPreload, bool aIsModule = false);
49 void NotifyOpen(const PreloadHashKey& aKey, nsIChannel* aChannel,
50 dom::Document* aDocument, bool aIsPreload,
51 bool aIsModule = false);
53 // Called when the load is about to be started all over again and thus this
54 // PreloaderBase will be registered again with the same key. This method
55 // taks care to deregister this preload prior to that.
56 // @param aNewPreloader: If there is a new request and loader created for the
57 // restarted load, we will pass any necessary information into it.
58 void NotifyRestart(dom::Document* aDocument,
59 PreloaderBase* aNewPreloader = nullptr);
61 // Called by the loading object when the channel started to load
62 // (OnStartRequest or equal) and when it finished (OnStopRequest or equal)
63 void NotifyStart(nsIRequest* aRequest);
64 void NotifyStop(nsIRequest* aRequest, nsresult aStatus);
65 // Use this variant only in complement to NotifyOpen without providing a
66 // channel.
67 void NotifyStop(nsresult aStatus);
69 // Called by resource loaders or any suitable component to notify the preload
70 // has been used for an actual load. This is intended to stop any usage
71 // timers.
72 // @param aDropLoadBackground: If `Keep` then the loading channel, if still in
73 // progress, will not be removed the LOAD_BACKGROUND flag, for instance XHR is
74 // the user here.
75 enum class LoadBackground { Keep, Drop };
76 void NotifyUsage(dom::Document* aDocument,
77 LoadBackground aLoadBackground = LoadBackground::Drop);
78 // Whether this preloader has been used for a regular/actual load or not.
79 bool IsUsed() const { return mIsUsed; }
81 // Removes itself from the document's preloads hashtable
82 void RemoveSelf(dom::Document* aDocument);
84 // When a loader starting an actual load finds a preload, the data can be
85 // delivered using this method. It will deliver stream listener notifications
86 // as if it were coming from the resource loading channel. The |request|
87 // argument will be the channel that loaded/loads the resource.
88 // This method must keep to the nsIChannel.AsyncOpen contract. A loader is
89 // not obligated to re-implement this method when not necessarily needed.
90 virtual nsresult AsyncConsume(nsIStreamListener* aListener);
92 // Accessor to the resource loading channel.
93 nsIChannel* Channel() const { return mChannel; }
95 // May change priority of the resource loading channel so that it's treated as
96 // preload when this was initially representing a normal speculative load but
97 // later <link rel="preload"> was found for this resource.
98 virtual void PrioritizeAsPreload() = 0;
100 // Helper function to set the LOAD_BACKGROUND flag on channel initiated by
101 // <link rel=preload>. This MUST be used before the channel is AsyncOpen'ed.
102 static void AddLoadBackgroundFlag(nsIChannel* aChannel);
104 // These are linking this preload to <link rel="preload"> DOM nodes. If we
105 // are already loaded, immediately notify events on the node, otherwise wait
106 // for NotifyStop() call.
107 void AddLinkPreloadNode(nsINode* aNode);
108 void RemoveLinkPreloadNode(nsINode* aNode);
110 // A collection of redirects, the main consumer is fetch.
111 class RedirectRecord {
112 public:
113 RedirectRecord(uint32_t aFlags, already_AddRefed<nsIURI> aURI)
114 : mFlags(aFlags), mURI(aURI) {}
116 uint32_t Flags() const { return mFlags; }
117 nsCString Spec() const;
118 nsCString Fragment() const;
120 private:
121 uint32_t mFlags;
122 nsCOMPtr<nsIURI> mURI;
125 const nsTArray<RedirectRecord>& Redirects() { return mRedirectRecords; }
127 void SetForEarlyHints() { mIsEarlyHintsPreload = true; }
129 protected:
130 virtual ~PreloaderBase();
132 // The loading channel. This will update when a redirect occurs.
133 nsCOMPtr<nsIChannel> mChannel;
135 private:
136 void NotifyNodeEvent(nsINode* aNode);
137 void CancelUsageTimer();
139 void ReportUsageTelemetry();
141 // A helper class that will update the PreloaderBase.mChannel member when a
142 // redirect happens, so that we can reprioritize or cancel when needed.
143 // Having a separate class instead of implementing this on PreloaderBase
144 // directly is to keep PreloaderBase as simple as possible so that derived
145 // classes don't have to deal with calling super when implementing these
146 // interfaces from some reason as well.
147 class RedirectSink;
149 // A timer callback to trigger the unuse warning for this preload
150 class UsageTimer final : public nsITimerCallback, public nsINamed {
151 NS_DECL_ISUPPORTS
152 NS_DECL_NSITIMERCALLBACK
153 NS_DECL_NSINAMED
155 UsageTimer(PreloaderBase* aPreload, dom::Document* aDocument);
157 private:
158 ~UsageTimer() = default;
160 WeakPtr<dom::Document> mDocument;
161 WeakPtr<PreloaderBase> mPreload;
164 private:
165 // Reference to HTMLLinkElement DOM nodes to deliver onload and onerror
166 // notifications to.
167 nsTArray<nsWeakPtr> mNodes;
169 // History of redirects.
170 nsTArray<RedirectRecord> mRedirectRecords;
172 // Usage timer, emits warning when the preload is not used in time. Started
173 // in NotifyOpen and stopped in NotifyUsage.
174 nsCOMPtr<nsITimer> mUsageTimer;
176 // The key this preload has been registered under. We want to remember it to
177 // be able to deregister itself from the document's preloads.
178 PreloadHashKey mKey;
180 // This overrides the final event we send to DOM nodes to be always 'load'.
181 // Modified in NotifyStart based on LoadInfo data of the loading channel.
182 bool mShouldFireLoadEvent = false;
184 // True after call to NotifyUsage.
185 bool mIsUsed = false;
187 // True after we have reported the usage telemetry. Prevent duplicates.
188 bool mUsageTelementryReported = false;
190 // True when this is used to Early Hints preload.
191 bool mIsEarlyHintsPreload = false;
193 // Emplaced when the data delivery has finished, in NotifyStop, holds the
194 // result of the load.
195 Maybe<nsresult> mOnStopStatus;
198 } // namespace mozilla
200 #endif // !PreloaderBase_h__