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/. */
6 #include "WorkletFetchHandler.h"
8 #include "js/loader/ModuleLoadRequest.h"
9 #include "js/ContextOptions.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/dom/Fetch.h"
12 #include "mozilla/dom/Request.h"
13 #include "mozilla/dom/RequestBinding.h"
14 #include "mozilla/dom/Response.h"
15 #include "mozilla/dom/RootedDictionary.h"
16 #include "mozilla/dom/ScriptLoader.h"
17 #include "mozilla/dom/ScriptLoadHandler.h" // ScriptDecoder
18 #include "mozilla/dom/Worklet.h"
19 #include "mozilla/dom/WorkletBinding.h"
20 #include "mozilla/dom/WorkletGlobalScope.h"
21 #include "mozilla/dom/WorkletImpl.h"
22 #include "mozilla/dom/WorkletThread.h"
23 #include "mozilla/dom/worklet/WorkletModuleLoader.h"
24 #include "mozilla/CycleCollectedJSContext.h"
25 #include "mozilla/ScopeExit.h"
26 #include "mozilla/TaskQueue.h"
27 #include "nsIInputStreamPump.h"
28 #include "nsIThreadRetargetableRequest.h"
29 #include "xpcpublic.h"
31 using JS::loader::ModuleLoadRequest
;
32 using JS::loader::ParserMetadata
;
33 using JS::loader::ScriptFetchOptions
;
34 using mozilla::dom::loader::WorkletModuleLoader
;
36 namespace mozilla::dom
{
38 // A Runnable to call ModuleLoadRequest::StartModuleLoad on a worklet thread.
39 class StartModuleLoadRunnable final
: public Runnable
{
41 StartModuleLoadRunnable(
42 WorkletImpl
* aWorkletImpl
,
43 const nsMainThreadPtrHandle
<WorkletFetchHandler
>& aHandlerRef
,
44 nsCOMPtr
<nsIURI
> aURI
, nsIURI
* aReferrer
,
45 const nsTArray
<nsString
>& aLocalizedStrs
)
46 : Runnable("Worklet::StartModuleLoadRunnable"),
47 mWorkletImpl(aWorkletImpl
),
48 mHandlerRef(aHandlerRef
),
49 mURI(std::move(aURI
)),
51 mLocalizedStrs(aLocalizedStrs
),
53 JS_GetParentRuntime(CycleCollectedJSContext::Get()->Context())) {
54 MOZ_ASSERT(NS_IsMainThread());
55 MOZ_ASSERT(mParentRuntime
);
56 xpc::SetPrefableContextOptions(mContextOptions
);
59 ~StartModuleLoadRunnable() = default;
61 NS_IMETHOD
Run() override
;
64 NS_IMETHOD
RunOnWorkletThread();
66 RefPtr
<WorkletImpl
> mWorkletImpl
;
67 nsMainThreadPtrHandle
<WorkletFetchHandler
> mHandlerRef
;
68 nsCOMPtr
<nsIURI
> mURI
;
69 nsCOMPtr
<nsIURI
> mReferrer
;
70 const nsTArray
<nsString
>& mLocalizedStrs
;
71 JSRuntime
* mParentRuntime
;
72 JS::ContextOptions mContextOptions
;
76 StartModuleLoadRunnable::Run() {
77 // WorkletThread::IsOnWorkletThread() cannot be used here because it depends
78 // on a WorkletJSContext having been created for this thread. That does not
79 // happen until the global scope is created the first time
80 // RunOnWorkletThread() is called.
81 MOZ_ASSERT(!NS_IsMainThread());
82 return RunOnWorkletThread();
85 NS_IMETHODIMP
StartModuleLoadRunnable::RunOnWorkletThread() {
86 // This can be called on a GraphRunner thread or a DOM Worklet thread.
87 WorkletThread::EnsureCycleCollectedJSContext(mParentRuntime
, mContextOptions
);
89 WorkletGlobalScope
* globalScope
= mWorkletImpl
->GetGlobalScope();
91 return NS_ERROR_DOM_UNKNOWN_ERR
;
94 // To fetch a worklet/module worker script graph:
95 // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-worklet/module-worker-script-graph
96 // Step 1. Let options be a script fetch options whose cryptographic nonce is
97 // the empty string, integrity metadata is the empty string, parser metadata
98 // is "not-parser-inserted", credentials mode is credentials mode, referrer
99 // policy is the empty string, and fetch priority is "auto".
100 RefPtr
<ScriptFetchOptions
> fetchOptions
= new ScriptFetchOptions(
101 CORSMode::CORS_NONE
, /* aNonce = */ u
""_ns
, RequestPriority::Auto
,
102 ParserMetadata::NotParserInserted
,
103 /*triggeringPrincipal*/ nullptr);
105 WorkletModuleLoader
* moduleLoader
=
106 static_cast<WorkletModuleLoader
*>(globalScope
->GetModuleLoader());
107 MOZ_ASSERT(moduleLoader
);
109 if (!moduleLoader
->HasSetLocalizedStrings()) {
110 moduleLoader
->SetLocalizedStrings(&mLocalizedStrs
);
113 RefPtr
<WorkletLoadContext
> loadContext
= new WorkletLoadContext(mHandlerRef
);
115 RefPtr
<JS::loader::VisitedURLSet
> visitedSet
=
116 ModuleLoadRequest::NewVisitedSetForTopLevelImport(
117 mURI
, JS::ModuleType::JavaScript
);
119 // Part of Step 2. This sets the Top-level flag to true
120 RefPtr
<ModuleLoadRequest
> request
= new ModuleLoadRequest(
121 mURI
, JS::ModuleType::JavaScript
, ReferrerPolicy::_empty
, fetchOptions
,
122 SRIMetadata(), mReferrer
, loadContext
, true, /* is top level */
123 false, /* is dynamic import */
124 moduleLoader
, visitedSet
, nullptr);
126 request
->mURL
= request
->mURI
->GetSpecOrDefault();
127 request
->NoCacheEntryFound();
129 return request
->StartModuleLoad();
132 StartFetchRunnable::StartFetchRunnable(
133 const nsMainThreadPtrHandle
<WorkletFetchHandler
>& aHandlerRef
, nsIURI
* aURI
,
135 : Runnable("Worklet::StartFetchRunnable"),
136 mHandlerRef(aHandlerRef
),
138 mReferrer(aReferrer
) {
139 MOZ_ASSERT(!NS_IsMainThread());
143 StartFetchRunnable::Run() {
144 MOZ_ASSERT(NS_IsMainThread());
146 nsCOMPtr
<nsIGlobalObject
> global
=
147 do_QueryInterface(mHandlerRef
->mWorklet
->GetParentObject());
151 if (NS_WARN_IF(!jsapi
.Init(global
))) {
152 return NS_ERROR_FAILURE
;
155 JSContext
* cx
= jsapi
.cx();
156 nsresult rv
= mHandlerRef
->StartFetch(cx
, mURI
, mReferrer
);
158 mHandlerRef
->HandleFetchFailed(mURI
);
159 return NS_ERROR_FAILURE
;
165 // A Runnable to call ModuleLoadRequest::OnFetchComplete on a worklet thread.
166 class FetchCompleteRunnable final
: public Runnable
{
168 FetchCompleteRunnable(WorkletImpl
* aWorkletImpl
, nsIURI
* aURI
,
170 UniquePtr
<uint8_t[]> aScriptBuffer
= nullptr,
171 size_t aScriptLength
= 0)
172 : Runnable("Worklet::FetchCompleteRunnable"),
173 mWorkletImpl(aWorkletImpl
),
176 mScriptBuffer(std::move(aScriptBuffer
)),
177 mScriptLength(aScriptLength
) {
178 MOZ_ASSERT(NS_IsMainThread());
181 ~FetchCompleteRunnable() = default;
183 NS_IMETHOD
Run() override
;
186 NS_IMETHOD
RunOnWorkletThread();
188 RefPtr
<WorkletImpl
> mWorkletImpl
;
189 nsCOMPtr
<nsIURI
> mURI
;
191 UniquePtr
<uint8_t[]> mScriptBuffer
;
192 size_t mScriptLength
;
196 FetchCompleteRunnable::Run() {
197 MOZ_ASSERT(WorkletThread::IsOnWorkletThread());
198 return RunOnWorkletThread();
201 NS_IMETHODIMP
FetchCompleteRunnable::RunOnWorkletThread() {
202 WorkletGlobalScope
* globalScope
= mWorkletImpl
->GetGlobalScope();
204 return NS_ERROR_DOM_UNKNOWN_ERR
;
207 WorkletModuleLoader
* moduleLoader
=
208 static_cast<WorkletModuleLoader
*>(globalScope
->GetModuleLoader());
209 MOZ_ASSERT(moduleLoader
);
211 ModuleLoadRequest
* request
= moduleLoader
->GetRequest(mURI
);
214 // Set the Source type to "text" for decoding.
215 request
->SetTextSource(request
->mLoadContext
.get());
219 UniquePtr
<ScriptDecoder
> decoder
= MakeUnique
<ScriptDecoder
>(
220 UTF_8_ENCODING
, ScriptDecoder::BOMHandling::Remove
);
221 rv
= decoder
->DecodeRawData(request
, mScriptBuffer
.get(), mScriptLength
,
223 NS_ENSURE_SUCCESS(rv
, rv
);
226 request
->mBaseURL
= mURI
;
227 request
->OnFetchComplete(mResult
);
229 if (NS_FAILED(mResult
)) {
230 if (request
->IsTopLevel()) {
231 request
->LoadFailed();
237 moduleLoader
->RemoveRequest(mURI
);
241 //////////////////////////////////////////////////////////////
242 // WorkletFetchHandler
243 //////////////////////////////////////////////////////////////
244 NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkletFetchHandler
)
245 NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkletFetchHandler
)
247 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkletFetchHandler
)
248 NS_INTERFACE_MAP_ENTRY(nsISupports
)
251 NS_IMPL_CYCLE_COLLECTION_CLASS(WorkletFetchHandler
)
253 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WorkletFetchHandler
)
254 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWorklet
, mPromises
)
255 tmp
->mErrorToRethrow
.setUndefined();
256 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
258 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WorkletFetchHandler
)
259 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWorklet
, mPromises
)
260 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
262 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WorkletFetchHandler
)
263 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow
)
264 NS_IMPL_CYCLE_COLLECTION_TRACE_END
267 already_AddRefed
<Promise
> WorkletFetchHandler::AddModule(
268 Worklet
* aWorklet
, JSContext
* aCx
, const nsAString
& aModuleURL
,
269 const WorkletOptions
& aOptions
, ErrorResult
& aRv
) {
270 MOZ_ASSERT(aWorklet
);
271 MOZ_ASSERT(NS_IsMainThread());
273 aWorklet
->Impl()->OnAddModuleStarted();
275 auto promiseSettledGuard
=
276 MakeScopeExit([&] { aWorklet
->Impl()->OnAddModulePromiseSettled(); });
278 nsCOMPtr
<nsIGlobalObject
> global
=
279 do_QueryInterface(aWorklet
->GetParentObject());
282 RefPtr
<Promise
> promise
= Promise::Create(global
, aRv
);
283 if (NS_WARN_IF(aRv
.Failed())) {
287 nsCOMPtr
<nsPIDOMWindowInner
> window
= aWorklet
->GetParentObject();
290 nsCOMPtr
<Document
> doc
;
291 doc
= window
->GetExtantDoc();
293 promise
->MaybeReject(NS_ERROR_FAILURE
);
294 return promise
.forget();
297 nsCOMPtr
<nsIURI
> resolvedURI
;
298 nsresult rv
= NS_NewURI(getter_AddRefs(resolvedURI
), aModuleURL
, nullptr,
300 if (NS_WARN_IF(NS_FAILED(rv
))) {
301 // https://html.spec.whatwg.org/multipage/worklets.html#dom-worklet-addmodule
302 // Step 3. If this fails, then return a promise rejected with a
303 // "SyntaxError" DOMException.
304 rv
= NS_ERROR_DOM_SYNTAX_ERR
;
306 promise
->MaybeReject(rv
);
307 return promise
.forget();
311 rv
= resolvedURI
->GetSpec(spec
);
312 if (NS_WARN_IF(NS_FAILED(rv
))) {
313 rv
= NS_ERROR_DOM_SYNTAX_ERR
;
315 promise
->MaybeReject(rv
);
316 return promise
.forget();
319 // Maybe we already have an handler for this URI
321 WorkletFetchHandler
* handler
= aWorklet
->GetImportFetchHandler(spec
);
323 handler
->AddPromise(aCx
, promise
);
324 return promise
.forget();
328 RefPtr
<WorkletFetchHandler
> handler
=
329 new WorkletFetchHandler(aWorklet
, promise
, aOptions
.mCredentials
);
331 nsMainThreadPtrHandle
<WorkletFetchHandler
> handlerRef
{
332 new nsMainThreadPtrHolder
<WorkletFetchHandler
>("FetchHandler", handler
)};
334 // Determine request's Referrer
335 // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
336 // Step 3. Switch on request’s referrer:
338 // Step 1.4. Let referrerSource be document’s URL.
339 nsIURI
* referrer
= doc
->GetDocumentURIAsReferrer();
340 nsCOMPtr
<nsIRunnable
> runnable
= new StartModuleLoadRunnable(
341 aWorklet
->mImpl
, handlerRef
, std::move(resolvedURI
), referrer
,
342 aWorklet
->GetLocalizedStrings());
344 if (NS_FAILED(aWorklet
->mImpl
->SendControlMessage(runnable
.forget()))) {
348 promiseSettledGuard
.release();
350 aWorklet
->AddImportFetchHandler(spec
, handler
);
351 return promise
.forget();
354 WorkletFetchHandler::WorkletFetchHandler(Worklet
* aWorklet
, Promise
* aPromise
,
355 RequestCredentials aCredentials
)
356 : mWorklet(aWorklet
), mStatus(ePending
), mCredentials(aCredentials
) {
357 MOZ_ASSERT(aWorklet
);
358 MOZ_ASSERT(aPromise
);
359 MOZ_ASSERT(NS_IsMainThread());
361 mPromises
.AppendElement(aPromise
);
364 WorkletFetchHandler::~WorkletFetchHandler() { mozilla::DropJSObjects(this); }
366 void WorkletFetchHandler::ExecutionFailed() {
367 MOZ_ASSERT(NS_IsMainThread());
368 RejectPromises(NS_ERROR_DOM_ABORT_ERR
);
371 void WorkletFetchHandler::ExecutionFailed(JS::Handle
<JS::Value
> aError
) {
372 MOZ_ASSERT(NS_IsMainThread());
373 RejectPromises(aError
);
376 void WorkletFetchHandler::ExecutionSucceeded() {
377 MOZ_ASSERT(NS_IsMainThread());
381 void WorkletFetchHandler::AddPromise(JSContext
* aCx
, Promise
* aPromise
) {
382 MOZ_ASSERT(aPromise
);
383 MOZ_ASSERT(NS_IsMainThread());
387 mPromises
.AppendElement(aPromise
);
392 JS::Rooted
<JS::Value
> error(aCx
, mErrorToRethrow
);
393 aPromise
->MaybeReject(error
);
395 aPromise
->MaybeReject(NS_ERROR_DOM_ABORT_ERR
);
400 aPromise
->MaybeResolveWithUndefined();
405 void WorkletFetchHandler::RejectPromises(nsresult aResult
) {
406 MOZ_ASSERT(mStatus
== ePending
);
407 MOZ_ASSERT(NS_FAILED(aResult
));
408 MOZ_ASSERT(NS_IsMainThread());
410 mWorklet
->Impl()->OnAddModulePromiseSettled();
412 for (uint32_t i
= 0; i
< mPromises
.Length(); ++i
) {
413 mPromises
[i
]->MaybeReject(aResult
);
421 void WorkletFetchHandler::RejectPromises(JS::Handle
<JS::Value
> aValue
) {
422 MOZ_ASSERT(mStatus
== ePending
);
423 MOZ_ASSERT(NS_IsMainThread());
425 mWorklet
->Impl()->OnAddModulePromiseSettled();
427 for (uint32_t i
= 0; i
< mPromises
.Length(); ++i
) {
428 mPromises
[i
]->MaybeReject(aValue
);
433 mErrorToRethrow
= aValue
;
435 mozilla::HoldJSObjects(this);
441 void WorkletFetchHandler::ResolvePromises() {
442 MOZ_ASSERT(mStatus
== ePending
);
443 MOZ_ASSERT(NS_IsMainThread());
445 mWorklet
->Impl()->OnAddModulePromiseSettled();
447 for (uint32_t i
= 0; i
< mPromises
.Length(); ++i
) {
448 mPromises
[i
]->MaybeResolveWithUndefined();
456 nsresult
WorkletFetchHandler::StartFetch(JSContext
* aCx
, nsIURI
* aURI
,
459 nsresult res
= aURI
->GetSpec(spec
);
460 if (NS_WARN_IF(NS_FAILED(res
))) {
461 return NS_ERROR_FAILURE
;
464 RequestOrUTF8String requestInput
;
465 requestInput
.SetAsUTF8String().ShareOrDependUpon(spec
);
467 RootedDictionary
<RequestInit
> requestInit(aCx
);
468 requestInit
.mCredentials
.Construct(mCredentials
);
470 // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
471 // Step 8. mode is "cors"
472 requestInit
.mMode
.Construct(RequestMode::Cors
);
475 res
= aReferrer
->GetSpec(requestInit
.mReferrer
.Construct());
476 if (NS_WARN_IF(NS_FAILED(res
))) {
477 return NS_ERROR_FAILURE
;
481 nsCOMPtr
<nsIGlobalObject
> global
=
482 do_QueryInterface(mWorklet
->GetParentObject());
485 // Note: added to infer a default credentials mode in the Request setup,
486 // but we always pass an explicit credentials value in requestInit, so
487 // this has no effect right now. Bug 1887862 covers fixing worklets to behave
488 // the same as "normal" fetch calls.
489 nsIPrincipal
* p
= global
->PrincipalOrNull();
490 CallerType callerType
= (p
&& p
->IsSystemPrincipal() ? CallerType::System
491 : CallerType::NonSystem
);
492 IgnoredErrorResult rv
;
493 SafeRefPtr
<Request
> request
= Request::Constructor(
494 global
, aCx
, requestInput
, requestInit
, callerType
, rv
);
496 return NS_ERROR_FAILURE
;
499 request
->OverrideContentPolicyType(mWorklet
->Impl()->ContentPolicyType());
501 RequestOrUTF8String finalRequestInput
;
502 finalRequestInput
.SetAsRequest() = request
.unsafeGetRawPtr();
504 RefPtr
<Promise
> fetchPromise
= FetchRequest(
505 global
, finalRequestInput
, requestInit
, CallerType::System
, rv
);
506 if (NS_WARN_IF(rv
.Failed())) {
507 return NS_ERROR_FAILURE
;
510 RefPtr
<WorkletScriptHandler
> scriptHandler
=
511 new WorkletScriptHandler(mWorklet
, aURI
);
512 fetchPromise
->AppendNativeHandler(scriptHandler
);
516 void WorkletFetchHandler::HandleFetchFailed(nsIURI
* aURI
) {
517 nsCOMPtr
<nsIRunnable
> runnable
= new FetchCompleteRunnable(
518 mWorklet
->mImpl
, aURI
, NS_ERROR_FAILURE
, nullptr, 0);
521 NS_FAILED(mWorklet
->mImpl
->SendControlMessage(runnable
.forget())))) {
522 NS_WARNING("Failed to dispatch FetchCompleteRunnable to a worklet thread.");
526 //////////////////////////////////////////////////////////////
527 // WorkletScriptHandler
528 //////////////////////////////////////////////////////////////
529 NS_IMPL_ISUPPORTS(WorkletScriptHandler
, nsIStreamLoaderObserver
)
531 WorkletScriptHandler::WorkletScriptHandler(Worklet
* aWorklet
, nsIURI
* aURI
)
532 : mWorklet(aWorklet
), mURI(aURI
) {}
534 void WorkletScriptHandler::ResolvedCallback(JSContext
* aCx
,
535 JS::Handle
<JS::Value
> aValue
,
537 MOZ_ASSERT(NS_IsMainThread());
539 if (!aValue
.isObject()) {
540 HandleFailure(NS_ERROR_FAILURE
);
544 RefPtr
<Response
> response
;
545 nsresult rv
= UNWRAP_OBJECT(Response
, &aValue
.toObject(), response
);
546 if (NS_WARN_IF(NS_FAILED(rv
))) {
547 HandleFailure(NS_ERROR_FAILURE
);
551 // https://html.spec.whatwg.org/multipage/worklets.html#dom-worklet-addmodule
552 // Step 6.4.1. If script is null, then:
553 // Step 1.1.2. Reject promise with an "AbortError" DOMException.
554 if (!response
->Ok()) {
555 HandleFailure(NS_ERROR_DOM_ABORT_ERR
);
559 nsCOMPtr
<nsIInputStream
> inputStream
;
560 response
->GetBody(getter_AddRefs(inputStream
));
562 HandleFailure(NS_ERROR_DOM_NETWORK_ERR
);
566 nsCOMPtr
<nsIInputStreamPump
> pump
;
567 rv
= NS_NewInputStreamPump(getter_AddRefs(pump
), inputStream
.forget());
568 if (NS_WARN_IF(NS_FAILED(rv
))) {
573 nsCOMPtr
<nsIStreamLoader
> loader
;
574 rv
= NS_NewStreamLoader(getter_AddRefs(loader
), this);
575 if (NS_WARN_IF(NS_FAILED(rv
))) {
580 rv
= pump
->AsyncRead(loader
);
581 if (NS_WARN_IF(NS_FAILED(rv
))) {
586 nsCOMPtr
<nsIThreadRetargetableRequest
> rr
= do_QueryInterface(pump
);
588 nsCOMPtr
<nsIEventTarget
> sts
=
589 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
590 RefPtr
<TaskQueue
> queue
= TaskQueue::Create(
591 sts
.forget(), "WorkletScriptHandler STS Delivery Queue");
592 rv
= rr
->RetargetDeliveryTo(queue
);
594 NS_WARNING("Failed to dispatch the nsIInputStreamPump to a IO thread.");
599 NS_IMETHODIMP
WorkletScriptHandler::OnStreamComplete(nsIStreamLoader
* aLoader
,
600 nsISupports
* aContext
,
603 const uint8_t* aString
) {
604 MOZ_ASSERT(NS_IsMainThread());
606 if (NS_FAILED(aStatus
)) {
607 HandleFailure(aStatus
);
611 // Copy the buffer and decode it on worklet thread, as we can only access
612 // ModuleLoadRequest on worklet thread.
613 UniquePtr
<uint8_t[]> scriptTextBuf
= MakeUnique
<uint8_t[]>(aStringLen
);
614 memcpy(scriptTextBuf
.get(), aString
, aStringLen
);
616 nsCOMPtr
<nsIRunnable
> runnable
= new FetchCompleteRunnable(
617 mWorklet
->mImpl
, mURI
, NS_OK
, std::move(scriptTextBuf
), aStringLen
);
619 if (NS_FAILED(mWorklet
->mImpl
->SendControlMessage(runnable
.forget()))) {
620 HandleFailure(NS_ERROR_FAILURE
);
626 void WorkletScriptHandler::RejectedCallback(JSContext
* aCx
,
627 JS::Handle
<JS::Value
> aValue
,
629 MOZ_ASSERT(NS_IsMainThread());
631 // https://html.spec.whatwg.org/multipage/worklets.html#dom-worklet-addmodule
632 // Step 6.4.1. If script is null, then:
633 // Step 1.1.2. Reject promise with an "AbortError" DOMException.
634 HandleFailure(NS_ERROR_DOM_ABORT_ERR
);
637 void WorkletScriptHandler::HandleFailure(nsresult aResult
) {
638 DispatchFetchCompleteToWorklet(aResult
);
641 void WorkletScriptHandler::DispatchFetchCompleteToWorklet(nsresult aRv
) {
642 nsCOMPtr
<nsIRunnable
> runnable
=
643 new FetchCompleteRunnable(mWorklet
->mImpl
, mURI
, aRv
, nullptr, 0);
646 NS_FAILED(mWorklet
->mImpl
->SendControlMessage(runnable
.forget())))) {
647 NS_WARNING("Failed to dispatch FetchCompleteRunnable to a worklet thread.");
651 } // namespace mozilla::dom