Bug 1874684 - Part 38: Enable now passing tests. r=allstarschh
[gecko.git] / dom / workers / WorkerScope.cpp
blob2121a99cb33cfa092ac23e7c7121a843e5abdbb9
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 #include "mozilla/dom/WorkerScope.h"
9 #include <stdio.h>
10 #include <new>
11 #include <utility>
12 #include "Crypto.h"
13 #include "GeckoProfiler.h"
14 #include "MainThreadUtils.h"
15 #include "ScriptLoader.h"
16 #include "js/CompilationAndEvaluation.h"
17 #include "js/CompileOptions.h"
18 #include "js/RealmOptions.h"
19 #include "js/RootingAPI.h"
20 #include "js/SourceText.h"
21 #include "js/Value.h"
22 #include "js/Wrapper.h"
23 #include "jsapi.h"
24 #include "jsfriendapi.h"
25 #include "mozilla/AlreadyAddRefed.h"
26 #include "mozilla/BaseProfilerMarkersPrerequisites.h"
27 #include "mozilla/CycleCollectedJSContext.h"
28 #include "mozilla/ErrorResult.h"
29 #include "mozilla/EventListenerManager.h"
30 #include "mozilla/Logging.h"
31 #include "mozilla/Maybe.h"
32 #include "mozilla/MozPromise.h"
33 #include "mozilla/Mutex.h"
34 #include "mozilla/NotNull.h"
35 #include "mozilla/RefPtr.h"
36 #include "mozilla/Result.h"
37 #include "mozilla/StaticAnalysisFunctions.h"
38 #include "mozilla/StorageAccess.h"
39 #include "mozilla/UniquePtr.h"
40 #include "mozilla/Unused.h"
41 #include "mozilla/dom/AutoEntryScript.h"
42 #include "mozilla/ipc/BackgroundChild.h"
43 #include "mozilla/dom/BindingDeclarations.h"
44 #include "mozilla/dom/BindingUtils.h"
45 #include "mozilla/dom/BlobURLProtocolHandler.h"
46 #include "mozilla/dom/CSPEvalChecker.h"
47 #include "mozilla/dom/CallbackDebuggerNotification.h"
48 #include "mozilla/dom/ClientSource.h"
49 #include "mozilla/dom/Clients.h"
50 #include "mozilla/dom/Console.h"
51 #include "mozilla/dom/DOMMozPromiseRequestHolder.h"
52 #include "mozilla/dom/DebuggerNotification.h"
53 #include "mozilla/dom/DebuggerNotificationBinding.h"
54 #include "mozilla/dom/DebuggerNotificationManager.h"
55 #include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
56 #include "mozilla/dom/DOMString.h"
57 #include "mozilla/dom/Fetch.h"
58 #include "mozilla/dom/FontFaceSet.h"
59 #include "mozilla/dom/IDBFactory.h"
60 #include "mozilla/dom/ImageBitmap.h"
61 #include "mozilla/dom/ImageBitmapSource.h"
62 #include "mozilla/dom/MessagePortBinding.h"
63 #include "mozilla/ipc/PBackgroundChild.h"
64 #include "mozilla/ipc/PBackgroundSharedTypes.h"
65 #include "mozilla/dom/Performance.h"
66 #include "mozilla/dom/Promise.h"
67 #include "mozilla/dom/PromiseWorkerProxy.h"
68 #include "mozilla/dom/WebTaskSchedulerWorker.h"
69 #include "mozilla/dom/ScriptSettings.h"
70 #include "mozilla/dom/SerializedStackHolder.h"
71 #include "mozilla/dom/ServiceWorkerDescriptor.h"
72 #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
73 #include "mozilla/dom/ServiceWorkerManager.h"
74 #include "mozilla/dom/ServiceWorkerRegistration.h"
75 #include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
76 #include "mozilla/dom/ServiceWorkerUtils.h"
77 #include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
78 #include "mozilla/dom/SimpleGlobalObject.h"
79 #include "mozilla/dom/TimeoutHandler.h"
80 #include "mozilla/dom/TestUtils.h"
81 #include "mozilla/dom/WorkerCommon.h"
82 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
83 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
84 #include "mozilla/dom/WorkerLocation.h"
85 #include "mozilla/dom/WorkerNavigator.h"
86 #include "mozilla/dom/WorkerPrivate.h"
87 #include "mozilla/dom/WorkerRunnable.h"
88 #include "mozilla/dom/WorkerDocumentListener.h"
89 #include "mozilla/dom/VsyncWorkerChild.h"
90 #include "mozilla/dom/cache/CacheStorage.h"
91 #include "mozilla/dom/cache/Types.h"
92 #include "mozilla/extensions/ExtensionBrowser.h"
93 #include "mozilla/fallible.h"
94 #include "mozilla/gfx/Rect.h"
95 #include "nsAtom.h"
96 #include "nsCOMPtr.h"
97 #include "nsContentUtils.h"
98 #include "nsDebug.h"
99 #include "nsGkAtoms.h"
100 #include "nsIEventTarget.h"
101 #include "nsIGlobalObject.h"
102 #include "nsIScriptError.h"
103 #include "nsISerialEventTarget.h"
104 #include "nsIWeakReference.h"
105 #include "nsJSUtils.h"
106 #include "nsLiteralString.h"
107 #include "nsQueryObject.h"
108 #include "nsReadableUtils.h"
109 #include "nsRFPService.h"
110 #include "nsString.h"
111 #include "nsTArray.h"
112 #include "nsTLiteralString.h"
113 #include "nsThreadUtils.h"
114 #include "nsWeakReference.h"
115 #include "nsWrapperCacheInlines.h"
116 #include "nscore.h"
117 #include "xpcpublic.h"
119 #ifdef ANDROID
120 # include <android/log.h>
121 #endif
123 #ifdef XP_WIN
124 # undef PostMessage
125 #endif
127 using mozilla::dom::cache::CacheStorage;
128 using mozilla::dom::workerinternals::NamedWorkerGlobalScopeMixin;
129 using mozilla::ipc::BackgroundChild;
130 using mozilla::ipc::PBackgroundChild;
131 using mozilla::ipc::PrincipalInfo;
133 namespace mozilla::dom {
135 static mozilla::LazyLogModule sWorkerScopeLog("WorkerScope");
137 #ifdef LOG
138 # undef LOG
139 #endif
140 #define LOG(args) MOZ_LOG(sWorkerScopeLog, LogLevel::Debug, args);
142 class WorkerScriptTimeoutHandler final : public ScriptTimeoutHandler {
143 public:
144 NS_DECL_ISUPPORTS_INHERITED
145 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WorkerScriptTimeoutHandler,
146 ScriptTimeoutHandler)
148 WorkerScriptTimeoutHandler(JSContext* aCx, nsIGlobalObject* aGlobal,
149 const nsAString& aExpression)
150 : ScriptTimeoutHandler(aCx, aGlobal, aExpression) {}
152 MOZ_CAN_RUN_SCRIPT virtual bool Call(const char* aExecutionReason) override;
154 private:
155 virtual ~WorkerScriptTimeoutHandler() = default;
158 NS_IMPL_CYCLE_COLLECTION_INHERITED(WorkerScriptTimeoutHandler,
159 ScriptTimeoutHandler)
161 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerScriptTimeoutHandler)
162 NS_INTERFACE_MAP_END_INHERITING(ScriptTimeoutHandler)
164 NS_IMPL_ADDREF_INHERITED(WorkerScriptTimeoutHandler, ScriptTimeoutHandler)
165 NS_IMPL_RELEASE_INHERITED(WorkerScriptTimeoutHandler, ScriptTimeoutHandler)
167 bool WorkerScriptTimeoutHandler::Call(const char* aExecutionReason) {
168 nsAutoMicroTask mt;
169 AutoEntryScript aes(mGlobal, aExecutionReason, false);
171 JSContext* cx = aes.cx();
172 JS::CompileOptions options(cx);
173 options.setFileAndLine(mFileName.get(), mLineNo).setNoScriptRval(true);
174 options.setIntroductionType("domTimer");
176 JS::Rooted<JS::Value> unused(cx);
177 JS::SourceText<char16_t> srcBuf;
178 if (!srcBuf.init(cx, mExpr.BeginReading(), mExpr.Length(),
179 JS::SourceOwnership::Borrowed) ||
180 !JS::Evaluate(cx, options, srcBuf, &unused)) {
181 if (!JS_IsExceptionPending(cx)) {
182 return false;
186 return true;
189 namespace workerinternals {
190 void NamedWorkerGlobalScopeMixin::GetName(DOMString& aName) const {
191 aName.AsAString() = mName;
193 } // namespace workerinternals
195 NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerGlobalScopeBase)
197 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScopeBase,
198 DOMEventTargetHelper)
199 tmp->AssertIsOnWorkerThread();
200 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
201 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mModuleLoader)
202 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSerialEventTarget)
203 tmp->TraverseObjectsInGlobal(cb);
204 // If we already exited WorkerThreadPrimaryRunnable, we will find it
205 // nullptr and there is nothing left to do here on the WorkerPrivate,
206 // in particular the timeouts have already been canceled and unlinked.
207 if (tmp->mWorkerPrivate) {
208 tmp->mWorkerPrivate->TraverseTimeouts(cb);
210 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
212 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScopeBase,
213 DOMEventTargetHelper)
214 tmp->AssertIsOnWorkerThread();
215 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
216 NS_IMPL_CYCLE_COLLECTION_UNLINK(mModuleLoader)
217 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSerialEventTarget)
218 tmp->UnlinkObjectsInGlobal();
219 // If we already exited WorkerThreadPrimaryRunnable, we will find it
220 // nullptr and there is nothing left to do here on the WorkerPrivate,
221 // in particular the timeouts have already been canceled and unlinked.
222 if (tmp->mWorkerPrivate) {
223 tmp->mWorkerPrivate->UnlinkTimeouts();
225 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
226 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
228 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScopeBase,
229 DOMEventTargetHelper)
230 tmp->AssertIsOnWorkerThread();
231 NS_IMPL_CYCLE_COLLECTION_TRACE_END
233 NS_IMPL_ADDREF_INHERITED(WorkerGlobalScopeBase, DOMEventTargetHelper)
234 NS_IMPL_RELEASE_INHERITED(WorkerGlobalScopeBase, DOMEventTargetHelper)
236 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerGlobalScopeBase)
237 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
238 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
239 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
241 WorkerGlobalScopeBase::WorkerGlobalScopeBase(
242 WorkerPrivate* aWorkerPrivate, UniquePtr<ClientSource> aClientSource)
243 : mWorkerPrivate(aWorkerPrivate),
244 mClientSource(std::move(aClientSource)),
245 mSerialEventTarget(aWorkerPrivate->HybridEventTarget()) {
246 LOG(("WorkerGlobalScopeBase::WorkerGlobalScopeBase [%p]", this));
247 MOZ_ASSERT(mWorkerPrivate);
248 #ifdef DEBUG
249 mWorkerPrivate->AssertIsOnWorkerThread();
250 mWorkerThreadUsedOnlyForAssert = PR_GetCurrentThread();
251 #endif
252 MOZ_ASSERT(mClientSource);
254 MOZ_DIAGNOSTIC_ASSERT(
255 mSerialEventTarget,
256 "There should be an event target when a worker global is created.");
258 // In workers, each DETH must have an owner. Because the global scope doesn't
259 // have one, let's set it as owner of itself.
260 BindToOwner(static_cast<nsIGlobalObject*>(this));
263 WorkerGlobalScopeBase::~WorkerGlobalScopeBase() = default;
265 JSObject* WorkerGlobalScopeBase::GetGlobalJSObject() {
266 AssertIsOnWorkerThread();
267 return GetWrapper();
270 JSObject* WorkerGlobalScopeBase::GetGlobalJSObjectPreserveColor() const {
271 AssertIsOnWorkerThread();
272 return GetWrapperPreserveColor();
275 bool WorkerGlobalScopeBase::IsSharedMemoryAllowed() const {
276 AssertIsOnWorkerThread();
277 return mWorkerPrivate->IsSharedMemoryAllowed();
280 bool WorkerGlobalScopeBase::ShouldResistFingerprinting(
281 RFPTarget aTarget) const {
282 AssertIsOnWorkerThread();
283 return mWorkerPrivate->ShouldResistFingerprinting(aTarget);
286 OriginTrials WorkerGlobalScopeBase::Trials() const {
287 AssertIsOnWorkerThread();
288 return mWorkerPrivate->Trials();
291 StorageAccess WorkerGlobalScopeBase::GetStorageAccess() {
292 AssertIsOnWorkerThread();
293 return mWorkerPrivate->StorageAccess();
296 Maybe<ClientInfo> WorkerGlobalScopeBase::GetClientInfo() const {
297 return Some(mClientSource->Info());
300 Maybe<ServiceWorkerDescriptor> WorkerGlobalScopeBase::GetController() const {
301 return mClientSource->GetController();
304 mozilla::Result<mozilla::ipc::PrincipalInfo, nsresult>
305 WorkerGlobalScopeBase::GetStorageKey() {
306 AssertIsOnWorkerThread();
308 const mozilla::ipc::PrincipalInfo& principalInfo =
309 mWorkerPrivate->GetEffectiveStoragePrincipalInfo();
311 // Block expanded and null principals, let content and system through.
312 if (principalInfo.type() !=
313 mozilla::ipc::PrincipalInfo::TContentPrincipalInfo &&
314 principalInfo.type() !=
315 mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo) {
316 return Err(NS_ERROR_DOM_SECURITY_ERR);
319 return principalInfo;
322 void WorkerGlobalScopeBase::Control(
323 const ServiceWorkerDescriptor& aServiceWorker) {
324 AssertIsOnWorkerThread();
325 MOZ_DIAGNOSTIC_ASSERT(!mWorkerPrivate->IsChromeWorker());
326 MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate->Kind() != WorkerKindService);
328 if (IsBlobURI(mWorkerPrivate->GetBaseURI())) {
329 // Blob URL workers can only become controlled by inheriting from
330 // their parent. Make sure to note this properly.
331 mClientSource->InheritController(aServiceWorker);
332 } else {
333 // Otherwise this is a normal interception and we simply record the
334 // controller locally.
335 mClientSource->SetController(aServiceWorker);
339 nsresult WorkerGlobalScopeBase::Dispatch(
340 already_AddRefed<nsIRunnable>&& aRunnable) const {
341 return SerialEventTarget()->Dispatch(std::move(aRunnable),
342 NS_DISPATCH_NORMAL);
345 nsISerialEventTarget* WorkerGlobalScopeBase::SerialEventTarget() const {
346 AssertIsOnWorkerThread();
347 return mSerialEventTarget;
350 // See also AutoJSAPI::ReportException
351 void WorkerGlobalScopeBase::ReportError(JSContext* aCx,
352 JS::Handle<JS::Value> aError,
353 CallerType, ErrorResult& aRv) {
354 JS::ErrorReportBuilder jsReport(aCx);
355 JS::ExceptionStack exnStack(aCx, aError, nullptr);
356 if (!jsReport.init(aCx, exnStack, JS::ErrorReportBuilder::NoSideEffects)) {
357 return aRv.NoteJSContextException(aCx);
360 // Before invoking ReportError, put the exception back on the context,
361 // because it may want to put it in its error events and has no other way
362 // to get hold of it. After we invoke ReportError, clear the exception on
363 // cx(), just in case ReportError didn't.
364 JS::SetPendingExceptionStack(aCx, exnStack);
365 mWorkerPrivate->ReportError(aCx, jsReport.toStringResult(),
366 jsReport.report());
367 JS_ClearPendingException(aCx);
370 void WorkerGlobalScopeBase::Atob(const nsAString& aAtob, nsAString& aOut,
371 ErrorResult& aRv) const {
372 AssertIsOnWorkerThread();
373 aRv = nsContentUtils::Atob(aAtob, aOut);
376 void WorkerGlobalScopeBase::Btoa(const nsAString& aBtoa, nsAString& aOut,
377 ErrorResult& aRv) const {
378 AssertIsOnWorkerThread();
379 aRv = nsContentUtils::Btoa(aBtoa, aOut);
382 already_AddRefed<Console> WorkerGlobalScopeBase::GetConsole(ErrorResult& aRv) {
383 AssertIsOnWorkerThread();
385 if (!mConsole) {
386 mConsole = Console::Create(mWorkerPrivate->GetJSContext(), nullptr, aRv);
387 if (NS_WARN_IF(aRv.Failed())) {
388 return nullptr;
392 RefPtr<Console> console = mConsole;
393 return console.forget();
396 uint64_t WorkerGlobalScopeBase::WindowID() const {
397 return mWorkerPrivate->WindowID();
400 NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerGlobalScope)
402 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope,
403 WorkerGlobalScopeBase)
404 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
405 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
406 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskScheduler)
407 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTrustedTypePolicyFactory)
408 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
409 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
410 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
411 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
412 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
413 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager)
414 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
416 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
417 WorkerGlobalScopeBase)
418 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
419 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
420 if (tmp->mWebTaskScheduler) {
421 tmp->mWebTaskScheduler->Disconnect();
422 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler)
424 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTrustedTypePolicyFactory)
425 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
426 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
427 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
428 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
429 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
430 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager)
431 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
433 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(WorkerGlobalScope,
434 WorkerGlobalScopeBase)
436 WorkerGlobalScope::~WorkerGlobalScope() = default;
438 void WorkerGlobalScope::NoteTerminating() {
439 LOG(("WorkerGlobalScope::NoteTerminating [%p]", this));
440 if (IsDying()) {
441 return;
444 StartDying();
447 void WorkerGlobalScope::NoteShuttingDown() {
448 MOZ_ASSERT(IsDying());
449 LOG(("WorkerGlobalScope::NoteShuttingDown [%p]", this));
451 if (mNavigator) {
452 mNavigator->Invalidate();
453 mNavigator = nullptr;
457 Crypto* WorkerGlobalScope::GetCrypto(ErrorResult& aError) {
458 AssertIsOnWorkerThread();
460 if (!mCrypto) {
461 mCrypto = new Crypto(this);
464 return mCrypto;
467 already_AddRefed<CacheStorage> WorkerGlobalScope::GetCaches(ErrorResult& aRv) {
468 if (!mCacheStorage) {
469 mCacheStorage = CacheStorage::CreateOnWorker(cache::DEFAULT_NAMESPACE, this,
470 mWorkerPrivate, aRv);
473 RefPtr<CacheStorage> ref = mCacheStorage;
474 return ref.forget();
477 bool WorkerGlobalScope::IsSecureContext() const {
478 bool globalSecure = JS::GetIsSecureContext(
479 js::GetNonCCWObjectRealm(GetWrapperPreserveColor()));
480 MOZ_ASSERT(globalSecure == mWorkerPrivate->IsSecureContext());
481 return globalSecure;
484 already_AddRefed<WorkerLocation> WorkerGlobalScope::Location() {
485 AssertIsOnWorkerThread();
487 if (!mLocation) {
488 mLocation = WorkerLocation::Create(mWorkerPrivate->GetLocationInfo());
489 MOZ_ASSERT(mLocation);
492 RefPtr<WorkerLocation> location = mLocation;
493 return location.forget();
496 already_AddRefed<WorkerNavigator> WorkerGlobalScope::Navigator() {
497 AssertIsOnWorkerThread();
499 if (!mNavigator) {
500 mNavigator = WorkerNavigator::Create(mWorkerPrivate->OnLine());
501 MOZ_ASSERT(mNavigator);
504 RefPtr<WorkerNavigator> navigator = mNavigator;
505 return navigator.forget();
508 already_AddRefed<WorkerNavigator> WorkerGlobalScope::GetExistingNavigator()
509 const {
510 AssertIsOnWorkerThread();
512 RefPtr<WorkerNavigator> navigator = mNavigator;
513 return navigator.forget();
516 FontFaceSet* WorkerGlobalScope::GetFonts(ErrorResult& aRv) {
517 AssertIsOnWorkerThread();
519 if (!mFontFaceSet) {
520 mFontFaceSet = FontFaceSet::CreateForWorker(this, mWorkerPrivate);
521 if (MOZ_UNLIKELY(!mFontFaceSet)) {
522 aRv.ThrowInvalidStateError("Couldn't acquire worker reference");
523 return nullptr;
527 return mFontFaceSet;
530 OnErrorEventHandlerNonNull* WorkerGlobalScope::GetOnerror() {
531 AssertIsOnWorkerThread();
533 EventListenerManager* elm = GetExistingListenerManager();
534 return elm ? elm->GetOnErrorEventHandler() : nullptr;
537 void WorkerGlobalScope::SetOnerror(OnErrorEventHandlerNonNull* aHandler) {
538 AssertIsOnWorkerThread();
540 EventListenerManager* elm = GetOrCreateListenerManager();
541 if (elm) {
542 elm->SetEventHandler(aHandler);
546 void WorkerGlobalScope::ImportScripts(JSContext* aCx,
547 const Sequence<nsString>& aScriptURLs,
548 ErrorResult& aRv) {
549 AssertIsOnWorkerThread();
551 UniquePtr<SerializedStackHolder> stack;
552 if (mWorkerPrivate->IsWatchedByDevTools()) {
553 stack = GetCurrentStackForNetMonitor(aCx);
557 AUTO_PROFILER_MARKER_TEXT(
558 "ImportScripts", JS, MarkerStack::Capture(),
559 profiler_thread_is_being_profiled_for_markers()
560 ? StringJoin(","_ns, aScriptURLs,
561 [](nsACString& dest, const auto& scriptUrl) {
562 AppendUTF16toUTF8(
563 Substring(
564 scriptUrl, 0,
565 std::min(size_t(128), scriptUrl.Length())),
566 dest);
568 : nsAutoCString{});
569 workerinternals::Load(mWorkerPrivate, std::move(stack), aScriptURLs,
570 WorkerScript, aRv);
574 int32_t WorkerGlobalScope::SetTimeout(JSContext* aCx, Function& aHandler,
575 const int32_t aTimeout,
576 const Sequence<JS::Value>& aArguments,
577 ErrorResult& aRv) {
578 return SetTimeoutOrInterval(aCx, aHandler, aTimeout, aArguments, false, aRv);
581 int32_t WorkerGlobalScope::SetTimeout(JSContext* aCx, const nsAString& aHandler,
582 const int32_t aTimeout,
583 const Sequence<JS::Value>& /* unused */,
584 ErrorResult& aRv) {
585 return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aRv);
588 void WorkerGlobalScope::ClearTimeout(int32_t aHandle) {
589 AssertIsOnWorkerThread();
591 DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearTimeout);
593 mWorkerPrivate->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
596 int32_t WorkerGlobalScope::SetInterval(JSContext* aCx, Function& aHandler,
597 const int32_t aTimeout,
598 const Sequence<JS::Value>& aArguments,
599 ErrorResult& aRv) {
600 return SetTimeoutOrInterval(aCx, aHandler, aTimeout, aArguments, true, aRv);
603 int32_t WorkerGlobalScope::SetInterval(JSContext* aCx,
604 const nsAString& aHandler,
605 const int32_t aTimeout,
606 const Sequence<JS::Value>& /* unused */,
607 ErrorResult& aRv) {
608 return SetTimeoutOrInterval(aCx, aHandler, aTimeout, true, aRv);
611 void WorkerGlobalScope::ClearInterval(int32_t aHandle) {
612 AssertIsOnWorkerThread();
614 DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearInterval);
616 mWorkerPrivate->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
619 int32_t WorkerGlobalScope::SetTimeoutOrInterval(
620 JSContext* aCx, Function& aHandler, const int32_t aTimeout,
621 const Sequence<JS::Value>& aArguments, bool aIsInterval, ErrorResult& aRv) {
622 AssertIsOnWorkerThread();
624 DebuggerNotificationDispatch(
625 this, aIsInterval ? DebuggerNotificationType::SetInterval
626 : DebuggerNotificationType::SetTimeout);
628 nsTArray<JS::Heap<JS::Value>> args;
629 if (!args.AppendElements(aArguments, fallible)) {
630 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
631 return 0;
634 RefPtr<TimeoutHandler> handler =
635 new CallbackTimeoutHandler(aCx, this, &aHandler, std::move(args));
637 return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, aIsInterval,
638 Timeout::Reason::eTimeoutOrInterval, aRv);
641 int32_t WorkerGlobalScope::SetTimeoutOrInterval(JSContext* aCx,
642 const nsAString& aHandler,
643 const int32_t aTimeout,
644 bool aIsInterval,
645 ErrorResult& aRv) {
646 AssertIsOnWorkerThread();
648 DebuggerNotificationDispatch(
649 this, aIsInterval ? DebuggerNotificationType::SetInterval
650 : DebuggerNotificationType::SetTimeout);
652 bool allowEval = false;
653 aRv =
654 CSPEvalChecker::CheckForWorker(aCx, mWorkerPrivate, aHandler, &allowEval);
655 if (NS_WARN_IF(aRv.Failed()) || !allowEval) {
656 return 0;
659 RefPtr<TimeoutHandler> handler =
660 new WorkerScriptTimeoutHandler(aCx, this, aHandler);
662 return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, aIsInterval,
663 Timeout::Reason::eTimeoutOrInterval, aRv);
666 void WorkerGlobalScope::GetOrigin(nsAString& aOrigin) const {
667 AssertIsOnWorkerThread();
668 nsContentUtils::GetWebExposedOriginSerialization(
669 mWorkerPrivate->GetPrincipal(), aOrigin);
672 bool WorkerGlobalScope::CrossOriginIsolated() const {
673 return mWorkerPrivate->CrossOriginIsolated();
676 void WorkerGlobalScope::Dump(const Optional<nsAString>& aString) const {
677 AssertIsOnWorkerThread();
679 if (!aString.WasPassed()) {
680 return;
683 if (!nsJSUtils::DumpEnabled()) {
684 return;
687 NS_ConvertUTF16toUTF8 str(aString.Value());
689 MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug,
690 ("[Worker.Dump] %s", str.get()));
691 #ifdef ANDROID
692 __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", str.get());
693 #endif
694 fputs(str.get(), stdout);
695 fflush(stdout);
698 Performance* WorkerGlobalScope::GetPerformance() {
699 AssertIsOnWorkerThread();
701 if (!mPerformance) {
702 mPerformance = Performance::CreateForWorker(this);
705 return mPerformance;
708 bool WorkerGlobalScope::IsInAutomation(JSContext* aCx, JSObject* /* unused */) {
709 return GetWorkerPrivateFromContext(aCx)->IsInAutomation();
712 void WorkerGlobalScope::GetJSTestingFunctions(
713 JSContext* aCx, JS::MutableHandle<JSObject*> aFunctions, ErrorResult& aRv) {
714 JSObject* obj = js::GetTestingFunctions(aCx);
715 if (!obj) {
716 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
717 return;
720 aFunctions.set(obj);
723 already_AddRefed<Promise> WorkerGlobalScope::Fetch(
724 const RequestOrUTF8String& aInput, const RequestInit& aInit,
725 CallerType aCallerType, ErrorResult& aRv) {
726 return FetchRequest(this, aInput, aInit, aCallerType, aRv);
729 already_AddRefed<IDBFactory> WorkerGlobalScope::GetIndexedDB(
730 JSContext* aCx, ErrorResult& aErrorResult) {
731 AssertIsOnWorkerThread();
733 RefPtr<IDBFactory> indexedDB = mIndexedDB;
735 if (!indexedDB) {
736 StorageAccess access = mWorkerPrivate->StorageAccess();
738 if (access == StorageAccess::eDeny) {
739 NS_WARNING("IndexedDB is not allowed in this worker!");
740 aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
741 return nullptr;
744 if (ShouldPartitionStorage(access) &&
745 !StoragePartitioningEnabled(access,
746 mWorkerPrivate->CookieJarSettings())) {
747 NS_WARNING("IndexedDB is not allowed in this worker!");
748 aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
749 return nullptr;
752 const PrincipalInfo& principalInfo =
753 mWorkerPrivate->GetEffectiveStoragePrincipalInfo();
755 auto res = IDBFactory::CreateForWorker(this, principalInfo,
756 mWorkerPrivate->WindowID());
757 if (NS_WARN_IF(res.isErr())) {
758 aErrorResult = res.unwrapErr();
759 return nullptr;
762 indexedDB = res.unwrap();
763 mIndexedDB = indexedDB;
766 return indexedDB.forget();
769 WebTaskScheduler* WorkerGlobalScope::Scheduler() {
770 mWorkerPrivate->AssertIsOnWorkerThread();
772 if (!mWebTaskScheduler) {
773 mWebTaskScheduler = WebTaskScheduler::CreateForWorker(mWorkerPrivate);
776 MOZ_ASSERT(mWebTaskScheduler);
777 return mWebTaskScheduler;
780 WebTaskScheduler* WorkerGlobalScope::GetExistingScheduler() const {
781 return mWebTaskScheduler;
784 already_AddRefed<Promise> WorkerGlobalScope::CreateImageBitmap(
785 const ImageBitmapSource& aImage, const ImageBitmapOptions& aOptions,
786 ErrorResult& aRv) {
787 return ImageBitmap::Create(this, aImage, Nothing(), aOptions, aRv);
790 already_AddRefed<Promise> WorkerGlobalScope::CreateImageBitmap(
791 const ImageBitmapSource& aImage, int32_t aSx, int32_t aSy, int32_t aSw,
792 int32_t aSh, const ImageBitmapOptions& aOptions, ErrorResult& aRv) {
793 return ImageBitmap::Create(
794 this, aImage, Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aOptions, aRv);
797 // https://html.spec.whatwg.org/#structured-cloning
798 void WorkerGlobalScope::StructuredClone(
799 JSContext* aCx, JS::Handle<JS::Value> aValue,
800 const StructuredSerializeOptions& aOptions,
801 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError) {
802 nsContentUtils::StructuredClone(aCx, this, aValue, aOptions, aRetval, aError);
805 mozilla::dom::DebuggerNotificationManager*
806 WorkerGlobalScope::GetOrCreateDebuggerNotificationManager() {
807 if (!mDebuggerNotificationManager) {
808 mDebuggerNotificationManager = new DebuggerNotificationManager(this);
811 return mDebuggerNotificationManager;
814 mozilla::dom::DebuggerNotificationManager*
815 WorkerGlobalScope::GetExistingDebuggerNotificationManager() {
816 return mDebuggerNotificationManager;
819 Maybe<EventCallbackDebuggerNotificationType>
820 WorkerGlobalScope::GetDebuggerNotificationType() const {
821 return Some(EventCallbackDebuggerNotificationType::Global);
824 RefPtr<ServiceWorkerRegistration>
825 WorkerGlobalScope::GetServiceWorkerRegistration(
826 const ServiceWorkerRegistrationDescriptor& aDescriptor) const {
827 AssertIsOnWorkerThread();
828 RefPtr<ServiceWorkerRegistration> ref;
829 ForEachGlobalTeardownObserver(
830 [&](GlobalTeardownObserver* aObserver, bool* aDoneOut) {
831 RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aObserver);
832 if (!swr || !swr->MatchesDescriptor(aDescriptor)) {
833 return;
836 ref = std::move(swr);
837 *aDoneOut = true;
839 return ref;
842 RefPtr<ServiceWorkerRegistration>
843 WorkerGlobalScope::GetOrCreateServiceWorkerRegistration(
844 const ServiceWorkerRegistrationDescriptor& aDescriptor) {
845 AssertIsOnWorkerThread();
846 RefPtr<ServiceWorkerRegistration> ref =
847 GetServiceWorkerRegistration(aDescriptor);
848 if (!ref) {
849 ref = ServiceWorkerRegistration::CreateForWorker(mWorkerPrivate, this,
850 aDescriptor);
852 return ref;
855 mozilla::dom::StorageManager* WorkerGlobalScope::GetStorageManager() {
856 return RefPtr(Navigator())->Storage();
859 // https://html.spec.whatwg.org/multipage/web-messaging.html#eligible-for-messaging
860 // * a WorkerGlobalScope object whose closing flag is false and whose worker
861 // is not a suspendable worker.
862 bool WorkerGlobalScope::IsEligibleForMessaging() {
863 return mIsEligibleForMessaging;
865 void WorkerGlobalScope::StorageAccessPermissionGranted() {
866 // Reset the IndexedDB factory.
867 mIndexedDB = nullptr;
869 // Reset DOM Cache
870 mCacheStorage = nullptr;
873 TrustedTypePolicyFactory* WorkerGlobalScope::TrustedTypes() {
874 if (!mTrustedTypePolicyFactory) {
875 mTrustedTypePolicyFactory = MakeRefPtr<TrustedTypePolicyFactory>(this);
878 return mTrustedTypePolicyFactory;
881 bool WorkerGlobalScope::WindowInteractionAllowed() const {
882 AssertIsOnWorkerThread();
883 return mWindowInteractionsAllowed > 0;
886 void WorkerGlobalScope::AllowWindowInteraction() {
887 AssertIsOnWorkerThread();
888 mWindowInteractionsAllowed++;
891 void WorkerGlobalScope::ConsumeWindowInteraction() {
892 AssertIsOnWorkerThread();
893 MOZ_ASSERT(mWindowInteractionsAllowed);
894 mWindowInteractionsAllowed--;
897 NS_IMPL_CYCLE_COLLECTION_INHERITED(DedicatedWorkerGlobalScope,
898 WorkerGlobalScope, mFrameRequestManager)
900 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DedicatedWorkerGlobalScope,
901 WorkerGlobalScope)
902 NS_IMPL_CYCLE_COLLECTION_TRACE_END
904 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(DedicatedWorkerGlobalScope,
905 WorkerGlobalScope)
907 DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
908 WorkerPrivate* aWorkerPrivate, UniquePtr<ClientSource> aClientSource,
909 const nsString& aName)
910 : WorkerGlobalScope(std::move(aWorkerPrivate), std::move(aClientSource)),
911 NamedWorkerGlobalScopeMixin(aName) {}
913 bool DedicatedWorkerGlobalScope::WrapGlobalObject(
914 JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
915 AssertIsOnWorkerThread();
916 MOZ_ASSERT(!mWorkerPrivate->IsSharedWorker());
918 JS::RealmOptions options;
919 mWorkerPrivate->CopyJSRealmOptions(options);
921 xpc::SetPrefableRealmOptions(options);
923 return DedicatedWorkerGlobalScope_Binding::Wrap(
924 aCx, this, this, options,
925 nsJSPrincipals::get(mWorkerPrivate->GetPrincipal()), aReflector);
928 void DedicatedWorkerGlobalScope::PostMessage(
929 JSContext* aCx, JS::Handle<JS::Value> aMessage,
930 const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) {
931 AssertIsOnWorkerThread();
932 mWorkerPrivate->PostMessageToParent(aCx, aMessage, aTransferable, aRv);
935 void DedicatedWorkerGlobalScope::PostMessage(
936 JSContext* aCx, JS::Handle<JS::Value> aMessage,
937 const StructuredSerializeOptions& aOptions, ErrorResult& aRv) {
938 AssertIsOnWorkerThread();
939 mWorkerPrivate->PostMessageToParent(aCx, aMessage, aOptions.mTransfer, aRv);
942 void DedicatedWorkerGlobalScope::Close() {
943 AssertIsOnWorkerThread();
944 mWorkerPrivate->CloseInternal();
947 int32_t DedicatedWorkerGlobalScope::RequestAnimationFrame(
948 FrameRequestCallback& aCallback, ErrorResult& aError) {
949 AssertIsOnWorkerThread();
951 DebuggerNotificationDispatch(this,
952 DebuggerNotificationType::RequestAnimationFrame);
954 // Ensure the worker is associated with a window.
955 if (mWorkerPrivate->WindowID() == UINT64_MAX) {
956 aError.ThrowNotSupportedError("Worker has no associated owner Window");
957 return 0;
960 if (!mVsyncChild) {
961 PBackgroundChild* bgChild = BackgroundChild::GetOrCreateForCurrentThread();
962 mVsyncChild = MakeRefPtr<VsyncWorkerChild>();
964 if (!bgChild || !mVsyncChild->Initialize(mWorkerPrivate) ||
965 !bgChild->SendPVsyncConstructor(mVsyncChild)) {
966 mVsyncChild->Destroy();
967 mVsyncChild = nullptr;
968 aError.ThrowNotSupportedError(
969 "Worker failed to register for vsync to drive event loop");
970 return 0;
974 if (!mDocListener) {
975 mDocListener = WorkerDocumentListener::Create(mWorkerPrivate);
976 if (!mDocListener) {
977 aError.ThrowNotSupportedError(
978 "Worker failed to register for document visibility events");
979 return 0;
983 int32_t handle = 0;
984 aError = mFrameRequestManager.Schedule(aCallback, &handle);
985 if (!aError.Failed() && mDocumentVisible) {
986 mVsyncChild->TryObserve();
988 return handle;
991 void DedicatedWorkerGlobalScope::CancelAnimationFrame(int32_t aHandle,
992 ErrorResult& aError) {
993 AssertIsOnWorkerThread();
995 DebuggerNotificationDispatch(this,
996 DebuggerNotificationType::CancelAnimationFrame);
998 // Ensure the worker is associated with a window.
999 if (mWorkerPrivate->WindowID() == UINT64_MAX) {
1000 aError.ThrowNotSupportedError("Worker has no associated owner Window");
1001 return;
1004 mFrameRequestManager.Cancel(aHandle);
1005 if (mVsyncChild && mFrameRequestManager.IsEmpty()) {
1006 mVsyncChild->TryUnobserve();
1010 void DedicatedWorkerGlobalScope::OnDocumentVisible(bool aVisible) {
1011 AssertIsOnWorkerThread();
1013 mDocumentVisible = aVisible;
1015 // We only change state immediately when we become visible. If we become
1016 // hidden, then we wait for the next vsync tick to apply that.
1017 if (aVisible && !mFrameRequestManager.IsEmpty()) {
1018 mVsyncChild->TryObserve();
1022 void DedicatedWorkerGlobalScope::OnVsync(const VsyncEvent& aVsync) {
1023 AssertIsOnWorkerThread();
1025 if (mFrameRequestManager.IsEmpty() || !mDocumentVisible) {
1026 // If we ever receive a vsync event, and there are still no callbacks to
1027 // process, or we remain hidden, we should disable observing them. By
1028 // waiting an extra tick, we ensure we minimize extra IPC for content that
1029 // does not call requestFrameAnimation directly during the callback, or
1030 // that is rapidly toggling between hidden and visible.
1031 mVsyncChild->TryUnobserve();
1032 return;
1035 nsTArray<FrameRequest> callbacks;
1036 mFrameRequestManager.Take(callbacks);
1038 RefPtr<DedicatedWorkerGlobalScope> scope(this);
1039 CallbackDebuggerNotificationGuard guard(
1040 scope, DebuggerNotificationType::RequestAnimationFrameCallback);
1042 // This is similar to what we do in nsRefreshDriver::RunFrameRequestCallbacks
1043 // and Performance::TimeStampToDOMHighResForRendering in order to have the
1044 // same behaviour for requestAnimationFrame on both the main and worker
1045 // threads.
1046 DOMHighResTimeStamp timeStamp = 0;
1047 if (!aVsync.mTime.IsNull()) {
1048 timeStamp = mWorkerPrivate->TimeStampToDOMHighRes(aVsync.mTime);
1049 // 0 is an inappropriate mixin for this this area; however CSS Animations
1050 // needs to have it's Time Reduction Logic refactored, so it's currently
1051 // only clamping for RFP mode. RFP mode gives a much lower time precision,
1052 // so we accept the security leak here for now.
1053 timeStamp = nsRFPService::ReduceTimePrecisionAsMSecsRFPOnly(
1054 timeStamp, 0, this->GetRTPCallerType());
1057 for (auto& callback : callbacks) {
1058 if (mFrameRequestManager.IsCanceled(callback.mHandle)) {
1059 continue;
1062 // MOZ_KnownLive is OK, because the stack array `callbacks` keeps the
1063 // callback alive and the mCallback strong reference can't be mutated by
1064 // the call.
1065 LogFrameRequestCallback::Run run(callback.mCallback);
1066 MOZ_KnownLive(callback.mCallback)->Call(timeStamp);
1070 SharedWorkerGlobalScope::SharedWorkerGlobalScope(
1071 WorkerPrivate* aWorkerPrivate, UniquePtr<ClientSource> aClientSource,
1072 const nsString& aName)
1073 : WorkerGlobalScope(std::move(aWorkerPrivate), std::move(aClientSource)),
1074 NamedWorkerGlobalScopeMixin(aName) {}
1076 bool SharedWorkerGlobalScope::WrapGlobalObject(
1077 JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
1078 AssertIsOnWorkerThread();
1079 MOZ_ASSERT(mWorkerPrivate->IsSharedWorker());
1081 JS::RealmOptions options;
1082 mWorkerPrivate->CopyJSRealmOptions(options);
1084 return SharedWorkerGlobalScope_Binding::Wrap(
1085 aCx, this, this, options,
1086 nsJSPrincipals::get(mWorkerPrivate->GetPrincipal()), aReflector);
1089 void SharedWorkerGlobalScope::Close() {
1090 AssertIsOnWorkerThread();
1091 mWorkerPrivate->CloseInternal();
1094 NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope,
1095 mClients, mExtensionBrowser, mRegistration)
1096 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerGlobalScope)
1097 NS_INTERFACE_MAP_END_INHERITING(WorkerGlobalScope)
1099 NS_IMPL_ADDREF_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope)
1100 NS_IMPL_RELEASE_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope)
1102 ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(
1103 WorkerPrivate* aWorkerPrivate, UniquePtr<ClientSource> aClientSource,
1104 const ServiceWorkerRegistrationDescriptor& aRegistrationDescriptor)
1105 : WorkerGlobalScope(std::move(aWorkerPrivate), std::move(aClientSource)),
1106 mScope(NS_ConvertUTF8toUTF16(aRegistrationDescriptor.Scope()))
1108 // Eagerly create the registration because we will need to receive
1109 // updates about the state of the registration. We can't wait until
1110 // first access to start receiving these.
1112 mRegistration(
1113 GetOrCreateServiceWorkerRegistration(aRegistrationDescriptor)) {}
1115 ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope() = default;
1117 bool ServiceWorkerGlobalScope::WrapGlobalObject(
1118 JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
1119 AssertIsOnWorkerThread();
1120 MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
1122 JS::RealmOptions options;
1123 mWorkerPrivate->CopyJSRealmOptions(options);
1125 return ServiceWorkerGlobalScope_Binding::Wrap(
1126 aCx, this, this, options,
1127 nsJSPrincipals::get(mWorkerPrivate->GetPrincipal()), aReflector);
1130 already_AddRefed<Clients> ServiceWorkerGlobalScope::GetClients() {
1131 if (!mClients) {
1132 mClients = new Clients(this);
1135 RefPtr<Clients> ref = mClients;
1136 return ref.forget();
1139 ServiceWorkerRegistration* ServiceWorkerGlobalScope::Registration() {
1140 return mRegistration;
1143 EventHandlerNonNull* ServiceWorkerGlobalScope::GetOnfetch() {
1144 AssertIsOnWorkerThread();
1146 return GetEventHandler(nsGkAtoms::onfetch);
1149 namespace {
1151 class ReportFetchListenerWarningRunnable final : public Runnable {
1152 const nsCString mScope;
1153 nsString mSourceSpec;
1154 uint32_t mLine;
1155 uint32_t mColumn;
1157 public:
1158 explicit ReportFetchListenerWarningRunnable(const nsString& aScope)
1159 : mozilla::Runnable("ReportFetchListenerWarningRunnable"),
1160 mScope(NS_ConvertUTF16toUTF8(aScope)) {
1161 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
1162 MOZ_ASSERT(workerPrivate);
1163 JSContext* cx = workerPrivate->GetJSContext();
1164 MOZ_ASSERT(cx);
1166 nsJSUtils::GetCallingLocation(cx, mSourceSpec, &mLine, &mColumn);
1169 NS_IMETHOD
1170 Run() override {
1171 AssertIsOnMainThread();
1173 ServiceWorkerManager::LocalizeAndReportToAllClients(
1174 mScope, "ServiceWorkerNoFetchHandler", nsTArray<nsString>{},
1175 nsIScriptError::warningFlag, mSourceSpec, u""_ns, mLine, mColumn);
1177 return NS_OK;
1181 } // anonymous namespace
1183 void ServiceWorkerGlobalScope::NoteFetchHandlerWasAdded() const {
1184 if (mWorkerPrivate->WorkerScriptExecutedSuccessfully()) {
1185 RefPtr<Runnable> r = new ReportFetchListenerWarningRunnable(mScope);
1186 mWorkerPrivate->DispatchToMainThreadForMessaging(r.forget());
1188 mWorkerPrivate->SetFetchHandlerWasAdded();
1191 void ServiceWorkerGlobalScope::SetOnfetch(
1192 mozilla::dom::EventHandlerNonNull* aCallback) {
1193 AssertIsOnWorkerThread();
1195 if (aCallback) {
1196 NoteFetchHandlerWasAdded();
1198 SetEventHandler(nsGkAtoms::onfetch, aCallback);
1201 void ServiceWorkerGlobalScope::EventListenerAdded(nsAtom* aType) {
1202 AssertIsOnWorkerThread();
1204 if (aType == nsGkAtoms::onfetch) {
1205 NoteFetchHandlerWasAdded();
1209 already_AddRefed<Promise> ServiceWorkerGlobalScope::SkipWaiting(
1210 ErrorResult& aRv) {
1211 AssertIsOnWorkerThread();
1212 MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
1214 RefPtr<Promise> promise = Promise::Create(this, aRv);
1215 if (NS_WARN_IF(aRv.Failed())) {
1216 return nullptr;
1219 using MozPromiseType =
1220 decltype(mWorkerPrivate->SetServiceWorkerSkipWaitingFlag())::element_type;
1221 auto holder = MakeRefPtr<DOMMozPromiseRequestHolder<MozPromiseType>>(this);
1223 mWorkerPrivate->SetServiceWorkerSkipWaitingFlag()
1224 ->Then(GetCurrentSerialEventTarget(), __func__,
1225 [holder, promise](const MozPromiseType::ResolveOrRejectValue&) {
1226 holder->Complete();
1227 promise->MaybeResolveWithUndefined();
1229 ->Track(*holder);
1231 return promise.forget();
1234 SafeRefPtr<extensions::ExtensionBrowser>
1235 ServiceWorkerGlobalScope::AcquireExtensionBrowser() {
1236 if (!mExtensionBrowser) {
1237 mExtensionBrowser = MakeSafeRefPtr<extensions::ExtensionBrowser>(this);
1240 return mExtensionBrowser.clonePtr();
1243 bool WorkerDebuggerGlobalScope::WrapGlobalObject(
1244 JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
1245 AssertIsOnWorkerThread();
1247 JS::RealmOptions options;
1248 mWorkerPrivate->CopyJSRealmOptions(options);
1250 return WorkerDebuggerGlobalScope_Binding::Wrap(
1251 aCx, this, this, options,
1252 nsJSPrincipals::get(mWorkerPrivate->GetPrincipal()), aReflector);
1255 void WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
1256 JS::MutableHandle<JSObject*> aGlobal,
1257 ErrorResult& aRv) {
1258 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
1259 if (!scope) {
1260 aRv.Throw(NS_ERROR_FAILURE);
1261 return;
1264 aGlobal.set(scope->GetWrapper());
1267 void WorkerDebuggerGlobalScope::CreateSandbox(
1268 JSContext* aCx, const nsAString& aName, JS::Handle<JSObject*> aPrototype,
1269 JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv) {
1270 AssertIsOnWorkerThread();
1272 aResult.set(nullptr);
1274 JS::Rooted<JS::Value> protoVal(aCx);
1275 protoVal.setObjectOrNull(aPrototype);
1276 JS::Rooted<JSObject*> sandbox(
1277 aCx,
1278 SimpleGlobalObject::Create(
1279 SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox, protoVal));
1281 if (!sandbox) {
1282 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
1283 return;
1286 if (!JS_WrapObject(aCx, &sandbox)) {
1287 aRv.NoteJSContextException(aCx);
1288 return;
1291 aResult.set(sandbox);
1294 void WorkerDebuggerGlobalScope::LoadSubScript(
1295 JSContext* aCx, const nsAString& aURL,
1296 const Optional<JS::Handle<JSObject*>>& aSandbox, ErrorResult& aRv) {
1297 AssertIsOnWorkerThread();
1299 Maybe<JSAutoRealm> ar;
1300 if (aSandbox.WasPassed()) {
1301 // We only care about worker debugger sandbox objects here, so
1302 // CheckedUnwrapStatic is fine.
1303 JS::Rooted<JSObject*> sandbox(aCx,
1304 js::CheckedUnwrapStatic(aSandbox.Value()));
1305 if (!sandbox || !IsWorkerDebuggerSandbox(sandbox)) {
1306 aRv.Throw(NS_ERROR_INVALID_ARG);
1307 return;
1310 ar.emplace(aCx, sandbox);
1313 nsTArray<nsString> urls;
1314 urls.AppendElement(aURL);
1315 workerinternals::Load(mWorkerPrivate, nullptr, urls, DebuggerScript, aRv);
1318 void WorkerDebuggerGlobalScope::EnterEventLoop() {
1319 // We're on the worker thread here, and WorkerPrivate's refcounting is
1320 // non-threadsafe: you can only do it on the parent thread. What that
1321 // means in practice is that we're relying on it being kept alive while
1322 // we run. Hopefully.
1323 MOZ_KnownLive(mWorkerPrivate)->EnterDebuggerEventLoop();
1326 void WorkerDebuggerGlobalScope::LeaveEventLoop() {
1327 mWorkerPrivate->LeaveDebuggerEventLoop();
1330 void WorkerDebuggerGlobalScope::PostMessage(const nsAString& aMessage) {
1331 mWorkerPrivate->PostMessageToDebugger(aMessage);
1334 void WorkerDebuggerGlobalScope::SetImmediate(Function& aHandler,
1335 ErrorResult& aRv) {
1336 mWorkerPrivate->SetDebuggerImmediate(aHandler, aRv);
1339 void WorkerDebuggerGlobalScope::ReportError(JSContext* aCx,
1340 const nsAString& aMessage) {
1341 JS::AutoFilename chars;
1342 uint32_t lineno = 0;
1343 JS::DescribeScriptedCaller(aCx, &chars, &lineno);
1344 nsString filename(NS_ConvertUTF8toUTF16(chars.get()));
1345 mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage);
1348 void WorkerDebuggerGlobalScope::RetrieveConsoleEvents(
1349 JSContext* aCx, nsTArray<JS::Value>& aEvents, ErrorResult& aRv) {
1350 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
1351 if (!scope) {
1352 aRv.Throw(NS_ERROR_FAILURE);
1353 return;
1356 RefPtr<Console> console = scope->GetConsole(aRv);
1357 if (NS_WARN_IF(aRv.Failed())) {
1358 return;
1361 console->RetrieveConsoleEvents(aCx, aEvents, aRv);
1364 void WorkerDebuggerGlobalScope::ClearConsoleEvents(JSContext* aCx,
1365 ErrorResult& aRv) {
1366 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
1367 if (!scope) {
1368 aRv.Throw(NS_ERROR_FAILURE);
1369 return;
1372 RefPtr<Console> console = scope->GetConsoleIfExists();
1373 if (console) {
1374 console->ClearStorage();
1378 void WorkerDebuggerGlobalScope::SetConsoleEventHandler(JSContext* aCx,
1379 AnyCallback* aHandler,
1380 ErrorResult& aRv) {
1381 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
1382 if (!scope) {
1383 aRv.Throw(NS_ERROR_FAILURE);
1384 return;
1387 RefPtr<Console> console = scope->GetConsole(aRv);
1388 if (NS_WARN_IF(aRv.Failed())) {
1389 return;
1392 console->SetConsoleEventHandler(aHandler);
1395 void WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
1396 const Optional<nsAString>& aString) const {
1397 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
1398 if (scope) {
1399 scope->Dump(aString);
1403 bool IsWorkerGlobal(JSObject* object) {
1404 return IS_INSTANCE_OF(WorkerGlobalScope, object);
1407 bool IsWorkerDebuggerGlobal(JSObject* object) {
1408 return IS_INSTANCE_OF(WorkerDebuggerGlobalScope, object);
1411 bool IsWorkerDebuggerSandbox(JSObject* object) {
1412 return SimpleGlobalObject::SimpleGlobalType(object) ==
1413 SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox;
1416 } // namespace mozilla::dom