Bug 1927077 - test(webgpu): update CTS to d473d09475bffec9569fe5c45834bb6aaad44818...
[gecko.git] / dom / worklet / WorkletFetchHandler.cpp
blob1d911f47a1062945f44ce78655e7ade98029283d
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 {
40 public:
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)),
50 mReferrer(aReferrer),
51 mLocalizedStrs(aLocalizedStrs),
52 mParentRuntime(
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;
63 private:
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;
75 NS_IMETHODIMP
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();
90 if (!globalScope) {
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,
134 nsIURI* aReferrer)
135 : Runnable("Worklet::StartFetchRunnable"),
136 mHandlerRef(aHandlerRef),
137 mURI(aURI),
138 mReferrer(aReferrer) {
139 MOZ_ASSERT(!NS_IsMainThread());
142 NS_IMETHODIMP
143 StartFetchRunnable::Run() {
144 MOZ_ASSERT(NS_IsMainThread());
146 nsCOMPtr<nsIGlobalObject> global =
147 do_QueryInterface(mHandlerRef->mWorklet->GetParentObject());
148 MOZ_ASSERT(global);
150 AutoJSAPI jsapi;
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);
157 if (NS_FAILED(rv)) {
158 mHandlerRef->HandleFetchFailed(mURI);
159 return NS_ERROR_FAILURE;
162 return NS_OK;
165 // A Runnable to call ModuleLoadRequest::OnFetchComplete on a worklet thread.
166 class FetchCompleteRunnable final : public Runnable {
167 public:
168 FetchCompleteRunnable(WorkletImpl* aWorkletImpl, nsIURI* aURI,
169 nsresult aResult,
170 UniquePtr<uint8_t[]> aScriptBuffer = nullptr,
171 size_t aScriptLength = 0)
172 : Runnable("Worklet::FetchCompleteRunnable"),
173 mWorkletImpl(aWorkletImpl),
174 mURI(aURI),
175 mResult(aResult),
176 mScriptBuffer(std::move(aScriptBuffer)),
177 mScriptLength(aScriptLength) {
178 MOZ_ASSERT(NS_IsMainThread());
181 ~FetchCompleteRunnable() = default;
183 NS_IMETHOD Run() override;
185 private:
186 NS_IMETHOD RunOnWorkletThread();
188 RefPtr<WorkletImpl> mWorkletImpl;
189 nsCOMPtr<nsIURI> mURI;
190 nsresult mResult;
191 UniquePtr<uint8_t[]> mScriptBuffer;
192 size_t mScriptLength;
195 NS_IMETHODIMP
196 FetchCompleteRunnable::Run() {
197 MOZ_ASSERT(WorkletThread::IsOnWorkletThread());
198 return RunOnWorkletThread();
201 NS_IMETHODIMP FetchCompleteRunnable::RunOnWorkletThread() {
202 WorkletGlobalScope* globalScope = mWorkletImpl->GetGlobalScope();
203 if (!globalScope) {
204 return NS_ERROR_DOM_UNKNOWN_ERR;
207 WorkletModuleLoader* moduleLoader =
208 static_cast<WorkletModuleLoader*>(globalScope->GetModuleLoader());
209 MOZ_ASSERT(moduleLoader);
210 MOZ_ASSERT(mURI);
211 ModuleLoadRequest* request = moduleLoader->GetRequest(mURI);
212 MOZ_ASSERT(request);
214 // Set the Source type to "text" for decoding.
215 request->SetTextSource(request->mLoadContext.get());
217 nsresult rv;
218 if (mScriptBuffer) {
219 UniquePtr<ScriptDecoder> decoder = MakeUnique<ScriptDecoder>(
220 UTF_8_ENCODING, ScriptDecoder::BOMHandling::Remove);
221 rv = decoder->DecodeRawData(request, mScriptBuffer.get(), mScriptLength,
222 true);
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();
232 } else {
233 request->Cancel();
237 moduleLoader->RemoveRequest(mURI);
238 return NS_OK;
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)
249 NS_INTERFACE_MAP_END
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
266 // static
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());
280 MOZ_ASSERT(global);
282 RefPtr<Promise> promise = Promise::Create(global, aRv);
283 if (NS_WARN_IF(aRv.Failed())) {
284 return nullptr;
287 nsCOMPtr<nsPIDOMWindowInner> window = aWorklet->GetParentObject();
288 MOZ_ASSERT(window);
290 nsCOMPtr<Document> doc;
291 doc = window->GetExtantDoc();
292 if (!doc) {
293 promise->MaybeReject(NS_ERROR_FAILURE);
294 return promise.forget();
297 nsCOMPtr<nsIURI> resolvedURI;
298 nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI), aModuleURL, nullptr,
299 doc->GetBaseURI());
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();
310 nsAutoCString spec;
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);
322 if (handler) {
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:
337 // "client"
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()))) {
345 return nullptr;
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());
378 ResolvePromises();
381 void WorkletFetchHandler::AddPromise(JSContext* aCx, Promise* aPromise) {
382 MOZ_ASSERT(aPromise);
383 MOZ_ASSERT(NS_IsMainThread());
385 switch (mStatus) {
386 case ePending:
387 mPromises.AppendElement(aPromise);
388 return;
390 case eRejected:
391 if (mHasError) {
392 JS::Rooted<JS::Value> error(aCx, mErrorToRethrow);
393 aPromise->MaybeReject(error);
394 } else {
395 aPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
397 return;
399 case eResolved:
400 aPromise->MaybeResolveWithUndefined();
401 return;
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);
415 mPromises.Clear();
417 mStatus = eRejected;
418 mWorklet = nullptr;
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);
430 mPromises.Clear();
432 mHasError = true;
433 mErrorToRethrow = aValue;
435 mozilla::HoldJSObjects(this);
437 mStatus = eRejected;
438 mWorklet = nullptr;
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();
450 mPromises.Clear();
452 mStatus = eResolved;
453 mWorklet = nullptr;
456 nsresult WorkletFetchHandler::StartFetch(JSContext* aCx, nsIURI* aURI,
457 nsIURI* aReferrer) {
458 nsAutoCString spec;
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);
474 if (aReferrer) {
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());
483 MOZ_ASSERT(global);
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);
495 if (rv.Failed()) {
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);
513 return NS_OK;
516 void WorkletFetchHandler::HandleFetchFailed(nsIURI* aURI) {
517 nsCOMPtr<nsIRunnable> runnable = new FetchCompleteRunnable(
518 mWorklet->mImpl, aURI, NS_ERROR_FAILURE, nullptr, 0);
520 if (NS_WARN_IF(
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,
536 ErrorResult& aRv) {
537 MOZ_ASSERT(NS_IsMainThread());
539 if (!aValue.isObject()) {
540 HandleFailure(NS_ERROR_FAILURE);
541 return;
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);
548 return;
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);
556 return;
559 nsCOMPtr<nsIInputStream> inputStream;
560 response->GetBody(getter_AddRefs(inputStream));
561 if (!inputStream) {
562 HandleFailure(NS_ERROR_DOM_NETWORK_ERR);
563 return;
566 nsCOMPtr<nsIInputStreamPump> pump;
567 rv = NS_NewInputStreamPump(getter_AddRefs(pump), inputStream.forget());
568 if (NS_WARN_IF(NS_FAILED(rv))) {
569 HandleFailure(rv);
570 return;
573 nsCOMPtr<nsIStreamLoader> loader;
574 rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
575 if (NS_WARN_IF(NS_FAILED(rv))) {
576 HandleFailure(rv);
577 return;
580 rv = pump->AsyncRead(loader);
581 if (NS_WARN_IF(NS_FAILED(rv))) {
582 HandleFailure(rv);
583 return;
586 nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(pump);
587 if (rr) {
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);
593 if (NS_FAILED(rv)) {
594 NS_WARNING("Failed to dispatch the nsIInputStreamPump to a IO thread.");
599 NS_IMETHODIMP WorkletScriptHandler::OnStreamComplete(nsIStreamLoader* aLoader,
600 nsISupports* aContext,
601 nsresult aStatus,
602 uint32_t aStringLen,
603 const uint8_t* aString) {
604 MOZ_ASSERT(NS_IsMainThread());
606 if (NS_FAILED(aStatus)) {
607 HandleFailure(aStatus);
608 return NS_OK;
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);
623 return NS_OK;
626 void WorkletScriptHandler::RejectedCallback(JSContext* aCx,
627 JS::Handle<JS::Value> aValue,
628 ErrorResult& aRv) {
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);
645 if (NS_WARN_IF(
646 NS_FAILED(mWorklet->mImpl->SendControlMessage(runnable.forget())))) {
647 NS_WARNING("Failed to dispatch FetchCompleteRunnable to a worklet thread.");
651 } // namespace mozilla::dom