Bug 1874684 - Part 6: Limit day length calculations to safe integers. r=mgaudet
[gecko.git] / dom / worklet / WorkletFetchHandler.cpp
blobb0c9ec1cfac43cc5b9ec2ab2a2293472ea41c8cd
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 // Part of Step 2. This sets the Top-level flag to true
116 RefPtr<ModuleLoadRequest> request = new ModuleLoadRequest(
117 mURI, ReferrerPolicy::_empty, fetchOptions, SRIMetadata(), mReferrer,
118 loadContext, true, /* is top level */
119 false, /* is dynamic import */
120 moduleLoader, ModuleLoadRequest::NewVisitedSetForTopLevelImport(mURI),
121 nullptr);
123 request->mURL = request->mURI->GetSpecOrDefault();
124 request->NoCacheEntryFound();
126 return request->StartModuleLoad();
129 StartFetchRunnable::StartFetchRunnable(
130 const nsMainThreadPtrHandle<WorkletFetchHandler>& aHandlerRef, nsIURI* aURI,
131 nsIURI* aReferrer)
132 : Runnable("Worklet::StartFetchRunnable"),
133 mHandlerRef(aHandlerRef),
134 mURI(aURI),
135 mReferrer(aReferrer) {
136 MOZ_ASSERT(!NS_IsMainThread());
139 NS_IMETHODIMP
140 StartFetchRunnable::Run() {
141 MOZ_ASSERT(NS_IsMainThread());
143 nsCOMPtr<nsIGlobalObject> global =
144 do_QueryInterface(mHandlerRef->mWorklet->GetParentObject());
145 MOZ_ASSERT(global);
147 AutoJSAPI jsapi;
148 if (NS_WARN_IF(!jsapi.Init(global))) {
149 return NS_ERROR_FAILURE;
152 JSContext* cx = jsapi.cx();
153 nsresult rv = mHandlerRef->StartFetch(cx, mURI, mReferrer);
154 if (NS_FAILED(rv)) {
155 mHandlerRef->HandleFetchFailed(mURI);
156 return NS_ERROR_FAILURE;
159 return NS_OK;
162 // A Runnable to call ModuleLoadRequest::OnFetchComplete on a worklet thread.
163 class FetchCompleteRunnable final : public Runnable {
164 public:
165 FetchCompleteRunnable(WorkletImpl* aWorkletImpl, nsIURI* aURI,
166 nsresult aResult,
167 UniquePtr<uint8_t[]> aScriptBuffer = nullptr,
168 size_t aScriptLength = 0)
169 : Runnable("Worklet::FetchCompleteRunnable"),
170 mWorkletImpl(aWorkletImpl),
171 mURI(aURI),
172 mResult(aResult),
173 mScriptBuffer(std::move(aScriptBuffer)),
174 mScriptLength(aScriptLength) {
175 MOZ_ASSERT(NS_IsMainThread());
178 ~FetchCompleteRunnable() = default;
180 NS_IMETHOD Run() override;
182 private:
183 NS_IMETHOD RunOnWorkletThread();
185 RefPtr<WorkletImpl> mWorkletImpl;
186 nsCOMPtr<nsIURI> mURI;
187 nsresult mResult;
188 UniquePtr<uint8_t[]> mScriptBuffer;
189 size_t mScriptLength;
192 NS_IMETHODIMP
193 FetchCompleteRunnable::Run() {
194 MOZ_ASSERT(WorkletThread::IsOnWorkletThread());
195 return RunOnWorkletThread();
198 NS_IMETHODIMP FetchCompleteRunnable::RunOnWorkletThread() {
199 WorkletGlobalScope* globalScope = mWorkletImpl->GetGlobalScope();
200 if (!globalScope) {
201 return NS_ERROR_DOM_UNKNOWN_ERR;
204 WorkletModuleLoader* moduleLoader =
205 static_cast<WorkletModuleLoader*>(globalScope->GetModuleLoader());
206 MOZ_ASSERT(moduleLoader);
207 MOZ_ASSERT(mURI);
208 ModuleLoadRequest* request = moduleLoader->GetRequest(mURI);
209 MOZ_ASSERT(request);
211 // Set the Source type to "text" for decoding.
212 request->SetTextSource(request->mLoadContext.get());
214 nsresult rv;
215 if (mScriptBuffer) {
216 UniquePtr<ScriptDecoder> decoder = MakeUnique<ScriptDecoder>(
217 UTF_8_ENCODING, ScriptDecoder::BOMHandling::Remove);
218 rv = decoder->DecodeRawData(request, mScriptBuffer.get(), mScriptLength,
219 true);
220 NS_ENSURE_SUCCESS(rv, rv);
223 request->mBaseURL = mURI;
224 request->OnFetchComplete(mResult);
226 if (NS_FAILED(mResult)) {
227 if (request->IsTopLevel()) {
228 request->LoadFailed();
229 } else {
230 request->Cancel();
234 moduleLoader->RemoveRequest(mURI);
235 return NS_OK;
238 //////////////////////////////////////////////////////////////
239 // WorkletFetchHandler
240 //////////////////////////////////////////////////////////////
241 NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkletFetchHandler)
242 NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkletFetchHandler)
244 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkletFetchHandler)
245 NS_INTERFACE_MAP_ENTRY(nsISupports)
246 NS_INTERFACE_MAP_END
248 NS_IMPL_CYCLE_COLLECTION_CLASS(WorkletFetchHandler)
250 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WorkletFetchHandler)
251 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWorklet, mPromises)
252 tmp->mErrorToRethrow.setUndefined();
253 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
255 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WorkletFetchHandler)
256 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWorklet, mPromises)
257 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
259 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WorkletFetchHandler)
260 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow)
261 NS_IMPL_CYCLE_COLLECTION_TRACE_END
263 // static
264 already_AddRefed<Promise> WorkletFetchHandler::AddModule(
265 Worklet* aWorklet, JSContext* aCx, const nsAString& aModuleURL,
266 const WorkletOptions& aOptions, ErrorResult& aRv) {
267 MOZ_ASSERT(aWorklet);
268 MOZ_ASSERT(NS_IsMainThread());
270 aWorklet->Impl()->OnAddModuleStarted();
272 auto promiseSettledGuard =
273 MakeScopeExit([&] { aWorklet->Impl()->OnAddModulePromiseSettled(); });
275 nsCOMPtr<nsIGlobalObject> global =
276 do_QueryInterface(aWorklet->GetParentObject());
277 MOZ_ASSERT(global);
279 RefPtr<Promise> promise = Promise::Create(global, aRv);
280 if (NS_WARN_IF(aRv.Failed())) {
281 return nullptr;
284 nsCOMPtr<nsPIDOMWindowInner> window = aWorklet->GetParentObject();
285 MOZ_ASSERT(window);
287 nsCOMPtr<Document> doc;
288 doc = window->GetExtantDoc();
289 if (!doc) {
290 promise->MaybeReject(NS_ERROR_FAILURE);
291 return promise.forget();
294 nsCOMPtr<nsIURI> resolvedURI;
295 nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI), aModuleURL, nullptr,
296 doc->GetBaseURI());
297 if (NS_WARN_IF(NS_FAILED(rv))) {
298 // https://html.spec.whatwg.org/multipage/worklets.html#dom-worklet-addmodule
299 // Step 3. If this fails, then return a promise rejected with a
300 // "SyntaxError" DOMException.
301 rv = NS_ERROR_DOM_SYNTAX_ERR;
303 promise->MaybeReject(rv);
304 return promise.forget();
307 nsAutoCString spec;
308 rv = resolvedURI->GetSpec(spec);
309 if (NS_WARN_IF(NS_FAILED(rv))) {
310 rv = NS_ERROR_DOM_SYNTAX_ERR;
312 promise->MaybeReject(rv);
313 return promise.forget();
316 // Maybe we already have an handler for this URI
318 WorkletFetchHandler* handler = aWorklet->GetImportFetchHandler(spec);
319 if (handler) {
320 handler->AddPromise(aCx, promise);
321 return promise.forget();
325 RefPtr<WorkletFetchHandler> handler =
326 new WorkletFetchHandler(aWorklet, promise, aOptions.mCredentials);
328 nsMainThreadPtrHandle<WorkletFetchHandler> handlerRef{
329 new nsMainThreadPtrHolder<WorkletFetchHandler>("FetchHandler", handler)};
331 // Determine request's Referrer
332 // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
333 // Step 3. Switch on request’s referrer:
334 // "client"
335 // Step 1.4. Let referrerSource be document’s URL.
336 nsIURI* referrer = doc->GetDocumentURIAsReferrer();
337 nsCOMPtr<nsIRunnable> runnable = new StartModuleLoadRunnable(
338 aWorklet->mImpl, handlerRef, std::move(resolvedURI), referrer,
339 aWorklet->GetLocalizedStrings());
341 if (NS_FAILED(aWorklet->mImpl->SendControlMessage(runnable.forget()))) {
342 return nullptr;
345 promiseSettledGuard.release();
347 aWorklet->AddImportFetchHandler(spec, handler);
348 return promise.forget();
351 WorkletFetchHandler::WorkletFetchHandler(Worklet* aWorklet, Promise* aPromise,
352 RequestCredentials aCredentials)
353 : mWorklet(aWorklet), mStatus(ePending), mCredentials(aCredentials) {
354 MOZ_ASSERT(aWorklet);
355 MOZ_ASSERT(aPromise);
356 MOZ_ASSERT(NS_IsMainThread());
358 mPromises.AppendElement(aPromise);
361 WorkletFetchHandler::~WorkletFetchHandler() { mozilla::DropJSObjects(this); }
363 void WorkletFetchHandler::ExecutionFailed() {
364 MOZ_ASSERT(NS_IsMainThread());
365 RejectPromises(NS_ERROR_DOM_ABORT_ERR);
368 void WorkletFetchHandler::ExecutionFailed(JS::Handle<JS::Value> aError) {
369 MOZ_ASSERT(NS_IsMainThread());
370 RejectPromises(aError);
373 void WorkletFetchHandler::ExecutionSucceeded() {
374 MOZ_ASSERT(NS_IsMainThread());
375 ResolvePromises();
378 void WorkletFetchHandler::AddPromise(JSContext* aCx, Promise* aPromise) {
379 MOZ_ASSERT(aPromise);
380 MOZ_ASSERT(NS_IsMainThread());
382 switch (mStatus) {
383 case ePending:
384 mPromises.AppendElement(aPromise);
385 return;
387 case eRejected:
388 if (mHasError) {
389 JS::Rooted<JS::Value> error(aCx, mErrorToRethrow);
390 aPromise->MaybeReject(error);
391 } else {
392 aPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
394 return;
396 case eResolved:
397 aPromise->MaybeResolveWithUndefined();
398 return;
402 void WorkletFetchHandler::RejectPromises(nsresult aResult) {
403 MOZ_ASSERT(mStatus == ePending);
404 MOZ_ASSERT(NS_FAILED(aResult));
405 MOZ_ASSERT(NS_IsMainThread());
407 mWorklet->Impl()->OnAddModulePromiseSettled();
409 for (uint32_t i = 0; i < mPromises.Length(); ++i) {
410 mPromises[i]->MaybeReject(aResult);
412 mPromises.Clear();
414 mStatus = eRejected;
415 mWorklet = nullptr;
418 void WorkletFetchHandler::RejectPromises(JS::Handle<JS::Value> aValue) {
419 MOZ_ASSERT(mStatus == ePending);
420 MOZ_ASSERT(NS_IsMainThread());
422 mWorklet->Impl()->OnAddModulePromiseSettled();
424 for (uint32_t i = 0; i < mPromises.Length(); ++i) {
425 mPromises[i]->MaybeReject(aValue);
427 mPromises.Clear();
429 mHasError = true;
430 mErrorToRethrow = aValue;
432 mozilla::HoldJSObjects(this);
434 mStatus = eRejected;
435 mWorklet = nullptr;
438 void WorkletFetchHandler::ResolvePromises() {
439 MOZ_ASSERT(mStatus == ePending);
440 MOZ_ASSERT(NS_IsMainThread());
442 mWorklet->Impl()->OnAddModulePromiseSettled();
444 for (uint32_t i = 0; i < mPromises.Length(); ++i) {
445 mPromises[i]->MaybeResolveWithUndefined();
447 mPromises.Clear();
449 mStatus = eResolved;
450 mWorklet = nullptr;
453 nsresult WorkletFetchHandler::StartFetch(JSContext* aCx, nsIURI* aURI,
454 nsIURI* aReferrer) {
455 nsAutoCString spec;
456 nsresult res = aURI->GetSpec(spec);
457 if (NS_WARN_IF(NS_FAILED(res))) {
458 return NS_ERROR_FAILURE;
461 RequestOrUTF8String requestInput;
462 requestInput.SetAsUTF8String().ShareOrDependUpon(spec);
464 RootedDictionary<RequestInit> requestInit(aCx);
465 requestInit.mCredentials.Construct(mCredentials);
467 // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
468 // Step 8. mode is "cors"
469 requestInit.mMode.Construct(RequestMode::Cors);
471 if (aReferrer) {
472 res = aReferrer->GetSpec(requestInit.mReferrer.Construct());
473 if (NS_WARN_IF(NS_FAILED(res))) {
474 return NS_ERROR_FAILURE;
478 nsCOMPtr<nsIGlobalObject> global =
479 do_QueryInterface(mWorklet->GetParentObject());
480 MOZ_ASSERT(global);
482 // Note: added to infer a default credentials mode in the Request setup,
483 // but we always pass an explicit credentials value in requestInit, so
484 // this has no effect right now. Bug 1887862 covers fixing worklets to behave
485 // the same as "normal" fetch calls.
486 nsIPrincipal* p = global->PrincipalOrNull();
487 CallerType callerType = (p && p->IsSystemPrincipal() ? CallerType::System
488 : CallerType::NonSystem);
489 IgnoredErrorResult rv;
490 SafeRefPtr<Request> request = Request::Constructor(
491 global, aCx, requestInput, requestInit, callerType, rv);
492 if (rv.Failed()) {
493 return NS_ERROR_FAILURE;
496 request->OverrideContentPolicyType(mWorklet->Impl()->ContentPolicyType());
498 RequestOrUTF8String finalRequestInput;
499 finalRequestInput.SetAsRequest() = request.unsafeGetRawPtr();
501 RefPtr<Promise> fetchPromise = FetchRequest(
502 global, finalRequestInput, requestInit, CallerType::System, rv);
503 if (NS_WARN_IF(rv.Failed())) {
504 return NS_ERROR_FAILURE;
507 RefPtr<WorkletScriptHandler> scriptHandler =
508 new WorkletScriptHandler(mWorklet, aURI);
509 fetchPromise->AppendNativeHandler(scriptHandler);
510 return NS_OK;
513 void WorkletFetchHandler::HandleFetchFailed(nsIURI* aURI) {
514 nsCOMPtr<nsIRunnable> runnable = new FetchCompleteRunnable(
515 mWorklet->mImpl, aURI, NS_ERROR_FAILURE, nullptr, 0);
517 if (NS_WARN_IF(
518 NS_FAILED(mWorklet->mImpl->SendControlMessage(runnable.forget())))) {
519 NS_WARNING("Failed to dispatch FetchCompleteRunnable to a worklet thread.");
523 //////////////////////////////////////////////////////////////
524 // WorkletScriptHandler
525 //////////////////////////////////////////////////////////////
526 NS_IMPL_ISUPPORTS(WorkletScriptHandler, nsIStreamLoaderObserver)
528 WorkletScriptHandler::WorkletScriptHandler(Worklet* aWorklet, nsIURI* aURI)
529 : mWorklet(aWorklet), mURI(aURI) {}
531 void WorkletScriptHandler::ResolvedCallback(JSContext* aCx,
532 JS::Handle<JS::Value> aValue,
533 ErrorResult& aRv) {
534 MOZ_ASSERT(NS_IsMainThread());
536 if (!aValue.isObject()) {
537 HandleFailure(NS_ERROR_FAILURE);
538 return;
541 RefPtr<Response> response;
542 nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response);
543 if (NS_WARN_IF(NS_FAILED(rv))) {
544 HandleFailure(NS_ERROR_FAILURE);
545 return;
548 // https://html.spec.whatwg.org/multipage/worklets.html#dom-worklet-addmodule
549 // Step 6.4.1. If script is null, then:
550 // Step 1.1.2. Reject promise with an "AbortError" DOMException.
551 if (!response->Ok()) {
552 HandleFailure(NS_ERROR_DOM_ABORT_ERR);
553 return;
556 nsCOMPtr<nsIInputStream> inputStream;
557 response->GetBody(getter_AddRefs(inputStream));
558 if (!inputStream) {
559 HandleFailure(NS_ERROR_DOM_NETWORK_ERR);
560 return;
563 nsCOMPtr<nsIInputStreamPump> pump;
564 rv = NS_NewInputStreamPump(getter_AddRefs(pump), inputStream.forget());
565 if (NS_WARN_IF(NS_FAILED(rv))) {
566 HandleFailure(rv);
567 return;
570 nsCOMPtr<nsIStreamLoader> loader;
571 rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
572 if (NS_WARN_IF(NS_FAILED(rv))) {
573 HandleFailure(rv);
574 return;
577 rv = pump->AsyncRead(loader);
578 if (NS_WARN_IF(NS_FAILED(rv))) {
579 HandleFailure(rv);
580 return;
583 nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(pump);
584 if (rr) {
585 nsCOMPtr<nsIEventTarget> sts =
586 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
587 RefPtr<TaskQueue> queue = TaskQueue::Create(
588 sts.forget(), "WorkletScriptHandler STS Delivery Queue");
589 rv = rr->RetargetDeliveryTo(queue);
590 if (NS_FAILED(rv)) {
591 NS_WARNING("Failed to dispatch the nsIInputStreamPump to a IO thread.");
596 NS_IMETHODIMP WorkletScriptHandler::OnStreamComplete(nsIStreamLoader* aLoader,
597 nsISupports* aContext,
598 nsresult aStatus,
599 uint32_t aStringLen,
600 const uint8_t* aString) {
601 MOZ_ASSERT(NS_IsMainThread());
603 if (NS_FAILED(aStatus)) {
604 HandleFailure(aStatus);
605 return NS_OK;
608 // Copy the buffer and decode it on worklet thread, as we can only access
609 // ModuleLoadRequest on worklet thread.
610 UniquePtr<uint8_t[]> scriptTextBuf = MakeUnique<uint8_t[]>(aStringLen);
611 memcpy(scriptTextBuf.get(), aString, aStringLen);
613 nsCOMPtr<nsIRunnable> runnable = new FetchCompleteRunnable(
614 mWorklet->mImpl, mURI, NS_OK, std::move(scriptTextBuf), aStringLen);
616 if (NS_FAILED(mWorklet->mImpl->SendControlMessage(runnable.forget()))) {
617 HandleFailure(NS_ERROR_FAILURE);
620 return NS_OK;
623 void WorkletScriptHandler::RejectedCallback(JSContext* aCx,
624 JS::Handle<JS::Value> aValue,
625 ErrorResult& aRv) {
626 MOZ_ASSERT(NS_IsMainThread());
628 // https://html.spec.whatwg.org/multipage/worklets.html#dom-worklet-addmodule
629 // Step 6.4.1. If script is null, then:
630 // Step 1.1.2. Reject promise with an "AbortError" DOMException.
631 HandleFailure(NS_ERROR_DOM_ABORT_ERR);
634 void WorkletScriptHandler::HandleFailure(nsresult aResult) {
635 DispatchFetchCompleteToWorklet(aResult);
638 void WorkletScriptHandler::DispatchFetchCompleteToWorklet(nsresult aRv) {
639 nsCOMPtr<nsIRunnable> runnable =
640 new FetchCompleteRunnable(mWorklet->mImpl, mURI, aRv, nullptr, 0);
642 if (NS_WARN_IF(
643 NS_FAILED(mWorklet->mImpl->SendControlMessage(runnable.forget())))) {
644 NS_WARNING("Failed to dispatch FetchCompleteRunnable to a worklet thread.");
648 } // namespace mozilla::dom