1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef js_loader_ScriptLoadRequest_h
8 #define js_loader_ScriptLoadRequest_h
10 #include "js/RootingAPI.h"
11 #include "js/SourceText.h"
12 #include "js/TypeDecls.h"
13 #include "mozilla/Atomics.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/dom/SRIMetadata.h"
16 #include "mozilla/LinkedList.h"
17 #include "mozilla/Maybe.h"
18 #include "mozilla/PreloaderBase.h"
19 #include "mozilla/StaticPrefs_dom.h"
20 #include "mozilla/Variant.h"
21 #include "mozilla/Vector.h"
22 #include "nsCycleCollectionParticipant.h"
23 #include "nsIGlobalObject.h"
24 #include "LoadedScript.h"
25 #include "ScriptKind.h"
26 #include "ScriptFetchOptions.h"
27 #include "nsIScriptElement.h"
29 class nsICacheInfoChannel
;
31 namespace mozilla::dom
{
33 class ScriptLoadContext
;
34 class WorkerLoadContext
;
35 class WorkletLoadContext
;
36 enum class RequestPriority
: uint8_t;
38 } // namespace mozilla::dom
40 namespace mozilla::loader
{
41 class SyncLoadContext
;
42 } // namespace mozilla::loader
47 class LoadContextBase
;
48 class ModuleLoadRequest
;
49 class ScriptLoadRequestList
;
54 * ScriptLoadRequest is a generic representation of a JavaScript script that
55 * will be loaded by a Script/Module loader. This representation is used by the
56 * DOM ScriptLoader and will be used by workers and MOZJSComponentLoader.
58 * The ScriptLoadRequest contains information about the kind of script (classic
59 * or module), the URI, and the ScriptFetchOptions associated with the script.
60 * It is responsible for holding the script data once the fetch is complete, or
61 * if the request is cached, the bytecode.
63 * Relationship to ScriptLoadContext:
65 * ScriptLoadRequest and ScriptLoadContexts have a circular pointer. A
66 * ScriptLoadContext augments the loading of a ScriptLoadRequest by providing
67 * additional information regarding the loading and evaluation behavior (see
68 * the ScriptLoadContext class for details). In terms of responsibility,
69 * the ScriptLoadRequest represents "What" is being loaded, and the
70 * ScriptLoadContext represents "How".
72 * TODO: see if we can use it in the jsshell script loader. We need to either
73 * remove ISUPPORTS or find a way to encorporate that in the jsshell. We would
74 * then only have one implementation of the script loader, and it would be
75 * tested whenever jsshell tests are run. This would mean finding another way to
76 * create ScriptLoadRequest lists.
80 class ScriptLoadRequest
: public nsISupports
,
81 private mozilla::LinkedListElement
<ScriptLoadRequest
>,
82 public LoadedScriptDelegate
<ScriptLoadRequest
> {
83 using super
= LinkedListElement
<ScriptLoadRequest
>;
85 // Allow LinkedListElement<ScriptLoadRequest> to cast us to itself as needed.
86 friend class mozilla::LinkedListElement
<ScriptLoadRequest
>;
87 friend class ScriptLoadRequestList
;
90 virtual ~ScriptLoadRequest();
93 using SRIMetadata
= mozilla::dom::SRIMetadata
;
94 ScriptLoadRequest(ScriptKind aKind
, nsIURI
* aURI
,
95 mozilla::dom::ReferrerPolicy aReferrerPolicy
,
96 ScriptFetchOptions
* aFetchOptions
,
97 const SRIMetadata
& aIntegrity
, nsIURI
* aReferrer
,
98 LoadContextBase
* aContext
);
100 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
101 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ScriptLoadRequest
)
103 using super::getNext
;
104 using super::isInList
;
106 template <typename T
, typename D
= JS::DeletePolicy
<T
>>
107 using UniquePtr
= mozilla::UniquePtr
<T
, D
>;
109 bool IsModuleRequest() const { return mKind
== ScriptKind::eModule
; }
110 bool IsImportMapRequest() const { return mKind
== ScriptKind::eImportMap
; }
112 ModuleLoadRequest
* AsModuleRequest();
113 const ModuleLoadRequest
* AsModuleRequest() const;
115 virtual bool IsTopLevel() const { return true; };
117 virtual void Cancel();
119 virtual void SetReady();
121 enum class State
: uint8_t {
123 PendingFetchingError
,
131 // Before any attempt at fetching resources from the cache we should first
132 // make sure that the resource does not yet exists in the cache. In which case
133 // we might simply alias its LoadedScript. Otherwise a new one would be
135 bool IsCheckingCache() const { return mState
== State::CheckingCache
; }
137 // Setup and load resources, to fill the LoadedScript and make it usable by
138 // the JavaScript engine.
139 bool IsFetching() const { return mState
== State::Fetching
; }
140 bool IsCompiling() const { return mState
== State::Compiling
; }
141 bool IsLoadingImports() const { return mState
== State::LoadingImports
; }
142 bool IsCanceled() const { return mState
== State::Canceled
; }
144 bool IsPendingFetchingError() const {
145 return mState
== State::PendingFetchingError
;
148 // Return whether the request has been completed, either successfully or
150 bool IsFinished() const {
151 return mState
== State::Ready
|| mState
== State::Canceled
;
154 mozilla::dom::RequestPriority
FetchPriority() const {
155 return mFetchOptions
->mFetchPriority
;
158 enum mozilla::dom::ReferrerPolicy
ReferrerPolicy() const {
159 return mReferrerPolicy
;
162 void UpdateReferrerPolicy(mozilla::dom::ReferrerPolicy aReferrerPolicy
) {
163 mReferrerPolicy
= aReferrerPolicy
;
166 enum ParserMetadata
ParserMetadata() const {
167 return mFetchOptions
->mParserMetadata
;
170 const nsString
& Nonce() const { return mFetchOptions
->mNonce
; }
172 nsIPrincipal
* TriggeringPrincipal() const {
173 return mFetchOptions
->mTriggeringPrincipal
;
176 // Convert a CheckingCache ScriptLoadRequest into a Fetching one, by creating
177 // a new LoadedScript which is matching the ScriptKind provided when
178 // constructing this ScriptLoadRequest.
179 void NoCacheEntryFound();
181 void SetPendingFetchingError();
183 void MarkForBytecodeEncoding(JSScript
* aScript
);
185 bool IsMarkedForBytecodeEncoding() const;
187 mozilla::CORSMode
CORSMode() const { return mFetchOptions
->mCORSMode
; }
189 void DropBytecodeCacheReferences();
191 bool HasLoadContext() const { return mLoadContext
; }
192 bool HasScriptLoadContext() const;
193 bool HasWorkerLoadContext() const;
195 mozilla::dom::ScriptLoadContext
* GetScriptLoadContext();
197 mozilla::loader::SyncLoadContext
* GetSyncLoadContext();
199 mozilla::dom::WorkerLoadContext
* GetWorkerLoadContext();
201 mozilla::dom::WorkletLoadContext
* GetWorkletLoadContext();
203 const LoadedScript
* getLoadedScript() const { return mLoadedScript
.get(); }
204 LoadedScript
* getLoadedScript() { return mLoadedScript
.get(); }
207 * Set the request's mBaseURL, based on aChannel.
208 * aOriginalURI is the result of aChannel->GetOriginalURI.
210 void SetBaseURLFromChannelAndOriginalURI(nsIChannel
* aChannel
,
211 nsIURI
* aOriginalURI
);
213 const ScriptKind mKind
; // Whether this is a classic script or a module
216 State mState
; // Are we still waiting for a load to complete?
217 bool mFetchSourceOnly
; // Request source, not cached bytecode.
219 // The referrer policy used for the initial fetch and for fetching any
221 enum mozilla::dom::ReferrerPolicy mReferrerPolicy
;
222 RefPtr
<ScriptFetchOptions
> mFetchOptions
;
223 const SRIMetadata mIntegrity
;
224 const nsCOMPtr
<nsIURI
> mReferrer
;
225 mozilla::Maybe
<nsString
>
226 mSourceMapURL
; // Holds source map url for loaded scripts
228 const nsCOMPtr
<nsIURI
> mURI
;
229 nsCOMPtr
<nsIPrincipal
> mOriginPrincipal
;
231 // Keep the URI's filename alive during off thread parsing.
232 // Also used by workers to report on errors while loading, and used by
233 // worklets as the file name in compile options.
236 // The base URL used for resolving relative module imports.
237 nsCOMPtr
<nsIURI
> mBaseURL
;
239 // The loaded script holds the source / bytecode which is loaded.
241 // Currently it is used to hold information which are needed by the Debugger.
242 // Soon it would be used as a way to dissociate the LoadRequest from the
243 // loaded value, such that multiple request referring to the same content
244 // would share the same loaded script.
245 RefPtr
<LoadedScript
> mLoadedScript
;
247 // Holds the top-level JSScript that corresponds to the current source, once
248 // it is parsed, and planned to be saved in the bytecode cache.
250 // NOTE: This field is not used for ModuleLoadRequest.
251 // See ModuleLoadRequest::mIsMarkedForBytecodeEncoding.
252 JS::Heap
<JSScript
*> mScriptForBytecodeEncoding
;
254 // Holds the Cache information, which is used to register the bytecode
255 // on the cache entry, such that we can load it the next time.
256 nsCOMPtr
<nsICacheInfoChannel
> mCacheInfo
;
258 // LoadContext for augmenting the load depending on the loading
259 // context (DOM, Worker, etc.)
260 RefPtr
<LoadContextBase
> mLoadContext
;
262 // EarlyHintRegistrar id to connect the http channel back to the preload, with
263 // a default of value of 0 indicating that this request is not an early hints
265 uint64_t mEarlyHintPreloaderId
;
268 class ScriptLoadRequestList
: private mozilla::LinkedList
<ScriptLoadRequest
> {
269 using super
= mozilla::LinkedList
<ScriptLoadRequest
>;
272 ~ScriptLoadRequestList();
274 void CancelRequestsAndClear();
277 bool Contains(ScriptLoadRequest
* aElem
) const;
280 using super::getFirst
;
281 using super::isEmpty
;
283 void AppendElement(ScriptLoadRequest
* aElem
) {
284 MOZ_ASSERT(!aElem
->isInList());
289 already_AddRefed
<ScriptLoadRequest
> Steal(ScriptLoadRequest
* aElem
) {
290 aElem
->removeFrom(*this);
291 return dont_AddRef(aElem
);
294 already_AddRefed
<ScriptLoadRequest
> StealFirst() {
295 MOZ_ASSERT(!isEmpty());
296 return Steal(getFirst());
299 void Remove(ScriptLoadRequest
* aElem
) {
300 aElem
->removeFrom(*this);
305 inline void ImplCycleCollectionUnlink(ScriptLoadRequestList
& aField
) {
306 while (!aField
.isEmpty()) {
307 RefPtr
<ScriptLoadRequest
> first
= aField
.StealFirst();
311 inline void ImplCycleCollectionTraverse(
312 nsCycleCollectionTraversalCallback
& aCallback
,
313 ScriptLoadRequestList
& aField
, const char* aName
, uint32_t aFlags
) {
314 for (ScriptLoadRequest
* request
= aField
.getFirst(); request
;
315 request
= request
->getNext()) {
316 CycleCollectionNoteChild(aCallback
, request
, aName
, aFlags
);
320 } // namespace loader
323 #endif // js_loader_ScriptLoadRequest_h