Bug 1861467 - [wpt-sync] Update web-platform-tests to eedf737ce39c512d0ca3471f988972e...
[gecko.git] / dom / workers / ScriptLoader.h
blob37b43fc0c6041922bf26102ffde8ac3927755a9e
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 mozilla_dom_workers_scriptloader_h__
8 #define mozilla_dom_workers_scriptloader_h__
10 #include "js/loader/ScriptLoadRequest.h"
11 #include "js/loader/ModuleLoadRequest.h"
12 #include "js/loader/ModuleLoaderBase.h"
13 #include "mozilla/dom/WorkerBinding.h"
14 #include "mozilla/dom/WorkerCommon.h"
15 #include "mozilla/dom/WorkerLoadContext.h"
16 #include "mozilla/dom/WorkerRef.h"
17 #include "mozilla/dom/workerinternals/WorkerModuleLoader.h"
18 #include "mozilla/Maybe.h"
19 #include "nsIContentPolicy.h"
20 #include "nsStringFwd.h"
21 #include "nsTArrayForwardDeclare.h"
23 class nsIChannel;
24 class nsICookieJarSettings;
25 class nsILoadGroup;
26 class nsIPrincipal;
27 class nsIReferrerInfo;
28 class nsIURI;
30 namespace mozilla {
32 class ErrorResult;
34 namespace dom {
36 class ClientInfo;
37 class Document;
38 struct WorkerLoadInfo;
39 class WorkerPrivate;
40 class SerializedStackHolder;
42 enum WorkerScriptType { WorkerScript, DebuggerScript };
44 namespace workerinternals {
46 namespace loader {
47 class ScriptExecutorRunnable;
48 class ScriptLoaderRunnable;
49 class CachePromiseHandler;
50 class CacheLoadHandler;
51 class CacheCreator;
52 class NetworkLoadHandler;
55 * [DOMDOC] WorkerScriptLoader
57 * The WorkerScriptLoader is the primary class responsible for loading all
58 * Workers, including: ServiceWorkers, SharedWorkers, RemoteWorkers, and
59 * dedicated Workers. Our implementation also includes a subtype of dedicated
60 * workers: ChromeWorker, which exposes information that isn't normally
61 * accessible on a dedicated worker. See [1] for more information.
63 * Due to constraints around fetching, this class currently delegates the
64 * "Fetch" portion of its work load to the main thread. Unlike the DOM
65 * ScriptLoader, the WorkerScriptLoader is not persistent and is not reused for
66 * subsequent loads. That means for each iteration of loading (for example,
67 * loading the main script, followed by a load triggered by ImportScripts), we
68 * recreate this class, and handle the case independently.
70 * The flow of requests across the boundaries looks like this:
72 * +----------------------------+
73 * | new WorkerScriptLoader(..) |
74 * +----------------------------+
75 * |
76 * V
77 * +-------------------------------------------+
78 * | WorkerScriptLoader::DispatchLoadScripts() |
79 * +-------------------------------------------+
80 * |
81 * V
82 * +............................+
83 * | new ScriptLoaderRunnable() |
84 * +............................+
85 * :
86 * V
87 * #####################################################################
88 * Enter Main thread
89 * #####################################################################
90 * :
91 * V
92 * +.............................+ For each: Is a normal Worker?
93 * | ScriptLoaderRunnable::Run() |----------------------------------+
94 * +.............................+ |
95 * | V
96 * | +----------------------------------+
97 * | | WorkerScriptLoader::LoadScript() |
98 * | +----------------------------------+
99 * | |
100 * | For each request: Is a ServiceWorker? |
101 * | |
102 * V V
103 * +==================+ No script in cache? +====================+
104 * | CacheLoadHandler |------------------------>| NetworkLoadHandler |
105 * +==================+ +====================+
106 * : :
107 * : Loaded from Cache : Loaded by Network
108 * : +..........................................+ :
109 * +---| ScriptLoaderRunnable::OnStreamComplete() |<----+
110 * +..........................................+
112 * | A request is ready, is it in post order?
114 * | call DispatchPendingProcessRequests()
115 * | This creates ScriptExecutorRunnable
116 * +..............................+
117 * | new ScriptLoaderExecutable() |
118 * +..............................+
121 * #####################################################################
122 * Enter worker thread
123 * #####################################################################
126 * +...............................+ All Scripts Executed?
127 * | ScriptLoaderExecutable::Run() | -------------+
128 * +...............................+ :
130 * : yes. Do execution
131 * : then shutdown.
134 * +--------------------------------------------+
135 * | WorkerScriptLoader::ShutdownScriptLoader() |
136 * +--------------------------------------------+
139 class WorkerScriptLoader : public JS::loader::ScriptLoaderInterface,
140 public nsINamed {
141 friend class ScriptExecutorRunnable;
142 friend class ScriptLoaderRunnable;
143 friend class CachePromiseHandler;
144 friend class CacheLoadHandler;
145 friend class CacheCreator;
146 friend class NetworkLoadHandler;
147 friend class WorkerModuleLoader;
149 RefPtr<ThreadSafeWorkerRef> mWorkerRef;
150 UniquePtr<SerializedStackHolder> mOriginStack;
151 nsString mOriginStackJSON;
152 nsCOMPtr<nsISerialEventTarget> mSyncLoopTarget;
153 ScriptLoadRequestList mLoadingRequests;
154 ScriptLoadRequestList mLoadedRequests;
155 Maybe<ServiceWorkerDescriptor> mController;
156 WorkerScriptType mWorkerScriptType;
157 ErrorResult& mRv;
158 bool mExecutionAborted = false;
159 bool mMutedErrorFlag = false;
161 // Count of loading module requests. mLoadingRequests doesn't keep track of
162 // child module requests.
163 // This member should be accessed on worker thread.
164 uint32_t mLoadingModuleRequestCount;
166 // Worker cancellation related Mutex
168 // Modified on the worker thread.
169 // It is ok to *read* this without a lock on the worker.
170 // Main thread must always acquire a lock.
171 bool mCleanedUp MOZ_GUARDED_BY(
172 mCleanUpLock); // To specify if the cleanUp() has been done.
174 Mutex& CleanUpLock() MOZ_RETURN_CAPABILITY(mCleanUpLock) {
175 return mCleanUpLock;
178 bool CleanedUp() const MOZ_REQUIRES(mCleanUpLock) {
179 mCleanUpLock.AssertCurrentThreadOwns();
180 return mCleanedUp;
183 // Ensure the worker and the main thread won't race to access |mCleanedUp|.
184 // Should be a MutexSingleWriter, but that causes a lot of issues when you
185 // expose the lock via Lock().
186 Mutex mCleanUpLock;
188 public:
189 NS_DECL_THREADSAFE_ISUPPORTS
191 WorkerScriptLoader(WorkerPrivate* aWorkerPrivate,
192 UniquePtr<SerializedStackHolder> aOriginStack,
193 nsISerialEventTarget* aSyncLoopTarget,
194 WorkerScriptType aWorkerScriptType, ErrorResult& aRv);
196 bool CreateScriptRequests(const nsTArray<nsString>& aScriptURLs,
197 const mozilla::Encoding* aDocumentEncoding,
198 bool aIsMainScript);
200 ScriptLoadRequest* GetMainScript();
202 already_AddRefed<ScriptLoadRequest> CreateScriptLoadRequest(
203 const nsString& aScriptURL, const mozilla::Encoding* aDocumentEncoding,
204 bool aIsMainScript);
206 bool DispatchLoadScript(ScriptLoadRequest* aRequest);
208 bool DispatchLoadScripts();
210 void TryShutdown();
212 WorkerScriptType GetWorkerScriptType() { return mWorkerScriptType; }
214 protected:
215 nsIURI* GetBaseURI() const override;
217 nsIURI* GetInitialBaseURI();
219 nsIGlobalObject* GetGlobal();
221 void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
223 bool StoreCSP();
225 bool ProcessPendingRequests(JSContext* aCx);
227 bool AllScriptsExecuted() {
228 return mLoadingRequests.isEmpty() && mLoadedRequests.isEmpty();
231 bool IsDebuggerScript() const { return mWorkerScriptType == DebuggerScript; }
233 void SetController(const Maybe<ServiceWorkerDescriptor>& aDescriptor) {
234 mController = aDescriptor;
237 Maybe<ServiceWorkerDescriptor>& GetController() { return mController; }
239 nsresult LoadScript(ThreadSafeRequestHandle* aRequestHandle);
241 void ShutdownScriptLoader(bool aResult, bool aMutedError);
243 private:
244 ~WorkerScriptLoader() = default;
246 NS_IMETHOD
247 GetName(nsACString& aName) override {
248 aName.AssignLiteral("WorkerScriptLoader");
249 return NS_OK;
252 void InitModuleLoader();
254 nsTArray<RefPtr<ThreadSafeRequestHandle>> GetLoadingList();
256 bool IsDynamicImport(ScriptLoadRequest* aRequest);
258 nsContentPolicyType GetContentPolicyType(ScriptLoadRequest* aRequest);
260 bool EvaluateScript(JSContext* aCx, ScriptLoadRequest* aRequest);
262 nsresult FillCompileOptionsForRequest(
263 JSContext* cx, ScriptLoadRequest* aRequest, JS::CompileOptions* aOptions,
264 JS::MutableHandle<JSScript*> aIntroductionScript) override;
266 void ReportErrorToConsole(ScriptLoadRequest* aRequest,
267 nsresult aResult) const override;
269 // Only used by import maps, crash if we get here.
270 void ReportWarningToConsole(
271 ScriptLoadRequest* aRequest, const char* aMessageName,
272 const nsTArray<nsString>& aParams = nsTArray<nsString>()) const override {
273 MOZ_CRASH("Import maps have not been implemented for this context");
276 void LogExceptionToConsole(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
278 bool AllModuleRequestsLoaded() const;
279 void IncreaseLoadingModuleRequestCount();
280 void DecreaseLoadingModuleRequestCount();
283 /* ScriptLoaderRunnable
285 * Responsibilities of this class:
286 * - the actual dispatch
287 * - delegating the load back to WorkerScriptLoader
288 * - handling the collections of scripts being requested
289 * - handling main thread cancellation
290 * - dispatching back to the worker thread
292 class ScriptLoaderRunnable final : public nsIRunnable, public nsINamed {
293 RefPtr<WorkerScriptLoader> mScriptLoader;
294 RefPtr<ThreadSafeWorkerRef> mWorkerRef;
295 nsTArrayView<RefPtr<ThreadSafeRequestHandle>> mLoadingRequests;
296 Maybe<nsresult> mCancelMainThread;
297 RefPtr<CacheCreator> mCacheCreator;
299 public:
300 NS_DECL_THREADSAFE_ISUPPORTS
302 explicit ScriptLoaderRunnable(
303 WorkerScriptLoader* aScriptLoader,
304 nsTArray<RefPtr<ThreadSafeRequestHandle>> aLoadingRequests);
306 nsresult OnStreamComplete(ThreadSafeRequestHandle* aRequestHandle,
307 nsresult aStatus);
309 void LoadingFinished(ThreadSafeRequestHandle* aRequestHandle, nsresult aRv);
311 void MaybeExecuteFinishedScripts(ThreadSafeRequestHandle* aRequestHandle);
313 bool IsCancelled() { return mCancelMainThread.isSome(); }
315 nsresult GetCancelResult() {
316 return (IsCancelled()) ? mCancelMainThread.ref() : NS_OK;
319 void CancelMainThreadWithBindingAborted();
321 CacheCreator* GetCacheCreator() { return mCacheCreator; };
323 private:
324 ~ScriptLoaderRunnable() = default;
326 void CancelMainThread(nsresult aCancelResult);
328 void DispatchProcessPendingRequests();
330 NS_IMETHOD
331 Run() override;
333 NS_IMETHOD
334 GetName(nsACString& aName) override {
335 aName.AssignLiteral("ScriptLoaderRunnable");
336 return NS_OK;
340 } // namespace loader
342 nsresult ChannelFromScriptURLMainThread(
343 nsIPrincipal* aPrincipal, Document* aParentDoc, nsILoadGroup* aLoadGroup,
344 nsIURI* aScriptURL, const WorkerType& aWorkerType,
345 const RequestCredentials& aCredentials,
346 const Maybe<ClientInfo>& aClientInfo,
347 nsContentPolicyType aContentPolicyType,
348 nsICookieJarSettings* aCookieJarSettings, nsIReferrerInfo* aReferrerInfo,
349 nsIChannel** aChannel);
351 nsresult ChannelFromScriptURLWorkerThread(
352 JSContext* aCx, WorkerPrivate* aParent, const nsAString& aScriptURL,
353 const WorkerType& aWorkerType, const RequestCredentials& aCredentials,
354 WorkerLoadInfo& aLoadInfo);
356 void ReportLoadError(ErrorResult& aRv, nsresult aLoadResult,
357 const nsAString& aScriptURL);
359 void LoadMainScript(WorkerPrivate* aWorkerPrivate,
360 UniquePtr<SerializedStackHolder> aOriginStack,
361 const nsAString& aScriptURL,
362 WorkerScriptType aWorkerScriptType, ErrorResult& aRv,
363 const mozilla::Encoding* aDocumentEncoding);
365 void Load(WorkerPrivate* aWorkerPrivate,
366 UniquePtr<SerializedStackHolder> aOriginStack,
367 const nsTArray<nsString>& aScriptURLs,
368 WorkerScriptType aWorkerScriptType, ErrorResult& aRv);
370 } // namespace workerinternals
372 } // namespace dom
373 } // namespace mozilla
375 #endif /* mozilla_dom_workers_scriptloader_h__ */