Bug 1861467 - [wpt-sync] Update web-platform-tests to eedf737ce39c512d0ca3471f988972e...
[gecko.git] / dom / workers / WorkerScope.cpp
blob8a2fdfa397a6bad94da68eacc8012ccac2827401
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(mLocation)
408 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
409 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
410 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
411 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
412 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager)
413 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
415 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
416 WorkerGlobalScopeBase)
417 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
418 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
419 if (tmp->mWebTaskScheduler) {
420 tmp->mWebTaskScheduler->Disconnect();
421 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler)
423 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
424 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
425 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
426 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
427 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
428 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager)
429 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
431 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(WorkerGlobalScope,
432 WorkerGlobalScopeBase)
434 WorkerGlobalScope::~WorkerGlobalScope() = default;
436 void WorkerGlobalScope::NoteTerminating() {
437 LOG(("WorkerGlobalScope::NoteTerminating [%p]", this));
438 if (IsDying()) {
439 return;
442 StartDying();
445 void WorkerGlobalScope::NoteShuttingDown() {
446 MOZ_ASSERT(IsDying());
447 LOG(("WorkerGlobalScope::NoteShuttingDown [%p]", this));
449 if (mNavigator) {
450 mNavigator->Invalidate();
451 mNavigator = nullptr;
455 Crypto* WorkerGlobalScope::GetCrypto(ErrorResult& aError) {
456 AssertIsOnWorkerThread();
458 if (!mCrypto) {
459 mCrypto = new Crypto(this);
462 return mCrypto;
465 already_AddRefed<CacheStorage> WorkerGlobalScope::GetCaches(ErrorResult& aRv) {
466 if (!mCacheStorage) {
467 mCacheStorage = CacheStorage::CreateOnWorker(cache::DEFAULT_NAMESPACE, this,
468 mWorkerPrivate, aRv);
471 RefPtr<CacheStorage> ref = mCacheStorage;
472 return ref.forget();
475 bool WorkerGlobalScope::IsSecureContext() const {
476 bool globalSecure = JS::GetIsSecureContext(
477 js::GetNonCCWObjectRealm(GetWrapperPreserveColor()));
478 MOZ_ASSERT(globalSecure == mWorkerPrivate->IsSecureContext());
479 return globalSecure;
482 already_AddRefed<WorkerLocation> WorkerGlobalScope::Location() {
483 AssertIsOnWorkerThread();
485 if (!mLocation) {
486 mLocation = WorkerLocation::Create(mWorkerPrivate->GetLocationInfo());
487 MOZ_ASSERT(mLocation);
490 RefPtr<WorkerLocation> location = mLocation;
491 return location.forget();
494 already_AddRefed<WorkerNavigator> WorkerGlobalScope::Navigator() {
495 AssertIsOnWorkerThread();
497 if (!mNavigator) {
498 mNavigator = WorkerNavigator::Create(mWorkerPrivate->OnLine());
499 MOZ_ASSERT(mNavigator);
502 RefPtr<WorkerNavigator> navigator = mNavigator;
503 return navigator.forget();
506 already_AddRefed<WorkerNavigator> WorkerGlobalScope::GetExistingNavigator()
507 const {
508 AssertIsOnWorkerThread();
510 RefPtr<WorkerNavigator> navigator = mNavigator;
511 return navigator.forget();
514 FontFaceSet* WorkerGlobalScope::GetFonts(ErrorResult& aRv) {
515 AssertIsOnWorkerThread();
517 if (!mFontFaceSet) {
518 mFontFaceSet = FontFaceSet::CreateForWorker(this, mWorkerPrivate);
519 if (MOZ_UNLIKELY(!mFontFaceSet)) {
520 aRv.ThrowInvalidStateError("Couldn't acquire worker reference");
521 return nullptr;
525 return mFontFaceSet;
528 OnErrorEventHandlerNonNull* WorkerGlobalScope::GetOnerror() {
529 AssertIsOnWorkerThread();
531 EventListenerManager* elm = GetExistingListenerManager();
532 return elm ? elm->GetOnErrorEventHandler() : nullptr;
535 void WorkerGlobalScope::SetOnerror(OnErrorEventHandlerNonNull* aHandler) {
536 AssertIsOnWorkerThread();
538 EventListenerManager* elm = GetOrCreateListenerManager();
539 if (elm) {
540 elm->SetEventHandler(aHandler);
544 void WorkerGlobalScope::ImportScripts(JSContext* aCx,
545 const Sequence<nsString>& aScriptURLs,
546 ErrorResult& aRv) {
547 AssertIsOnWorkerThread();
549 UniquePtr<SerializedStackHolder> stack;
550 if (mWorkerPrivate->IsWatchedByDevTools()) {
551 stack = GetCurrentStackForNetMonitor(aCx);
555 AUTO_PROFILER_MARKER_TEXT(
556 "ImportScripts", JS, MarkerStack::Capture(),
557 profiler_thread_is_being_profiled_for_markers()
558 ? StringJoin(","_ns, aScriptURLs,
559 [](nsACString& dest, const auto& scriptUrl) {
560 AppendUTF16toUTF8(
561 Substring(
562 scriptUrl, 0,
563 std::min(size_t(128), scriptUrl.Length())),
564 dest);
566 : nsAutoCString{});
567 workerinternals::Load(mWorkerPrivate, std::move(stack), aScriptURLs,
568 WorkerScript, aRv);
572 int32_t WorkerGlobalScope::SetTimeout(JSContext* aCx, Function& aHandler,
573 const int32_t aTimeout,
574 const Sequence<JS::Value>& aArguments,
575 ErrorResult& aRv) {
576 return SetTimeoutOrInterval(aCx, aHandler, aTimeout, aArguments, false, aRv);
579 int32_t WorkerGlobalScope::SetTimeout(JSContext* aCx, const nsAString& aHandler,
580 const int32_t aTimeout,
581 const Sequence<JS::Value>& /* unused */,
582 ErrorResult& aRv) {
583 return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aRv);
586 void WorkerGlobalScope::ClearTimeout(int32_t aHandle) {
587 AssertIsOnWorkerThread();
589 DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearTimeout);
591 mWorkerPrivate->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
594 int32_t WorkerGlobalScope::SetInterval(JSContext* aCx, Function& aHandler,
595 const int32_t aTimeout,
596 const Sequence<JS::Value>& aArguments,
597 ErrorResult& aRv) {
598 return SetTimeoutOrInterval(aCx, aHandler, aTimeout, aArguments, true, aRv);
601 int32_t WorkerGlobalScope::SetInterval(JSContext* aCx,
602 const nsAString& aHandler,
603 const int32_t aTimeout,
604 const Sequence<JS::Value>& /* unused */,
605 ErrorResult& aRv) {
606 return SetTimeoutOrInterval(aCx, aHandler, aTimeout, true, aRv);
609 void WorkerGlobalScope::ClearInterval(int32_t aHandle) {
610 AssertIsOnWorkerThread();
612 DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearInterval);
614 mWorkerPrivate->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
617 int32_t WorkerGlobalScope::SetTimeoutOrInterval(
618 JSContext* aCx, Function& aHandler, const int32_t aTimeout,
619 const Sequence<JS::Value>& aArguments, bool aIsInterval, ErrorResult& aRv) {
620 AssertIsOnWorkerThread();
622 DebuggerNotificationDispatch(
623 this, aIsInterval ? DebuggerNotificationType::SetInterval
624 : DebuggerNotificationType::SetTimeout);
626 nsTArray<JS::Heap<JS::Value>> args;
627 if (!args.AppendElements(aArguments, fallible)) {
628 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
629 return 0;
632 RefPtr<TimeoutHandler> handler =
633 new CallbackTimeoutHandler(aCx, this, &aHandler, std::move(args));
635 return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, aIsInterval,
636 Timeout::Reason::eTimeoutOrInterval, aRv);
639 int32_t WorkerGlobalScope::SetTimeoutOrInterval(JSContext* aCx,
640 const nsAString& aHandler,
641 const int32_t aTimeout,
642 bool aIsInterval,
643 ErrorResult& aRv) {
644 AssertIsOnWorkerThread();
646 DebuggerNotificationDispatch(
647 this, aIsInterval ? DebuggerNotificationType::SetInterval
648 : DebuggerNotificationType::SetTimeout);
650 bool allowEval = false;
651 aRv =
652 CSPEvalChecker::CheckForWorker(aCx, mWorkerPrivate, aHandler, &allowEval);
653 if (NS_WARN_IF(aRv.Failed()) || !allowEval) {
654 return 0;
657 RefPtr<TimeoutHandler> handler =
658 new WorkerScriptTimeoutHandler(aCx, this, aHandler);
660 return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, aIsInterval,
661 Timeout::Reason::eTimeoutOrInterval, aRv);
664 void WorkerGlobalScope::GetOrigin(nsAString& aOrigin) const {
665 AssertIsOnWorkerThread();
666 nsContentUtils::GetWebExposedOriginSerialization(
667 mWorkerPrivate->GetPrincipal(), aOrigin);
670 bool WorkerGlobalScope::CrossOriginIsolated() const {
671 return mWorkerPrivate->CrossOriginIsolated();
674 void WorkerGlobalScope::Dump(const Optional<nsAString>& aString) const {
675 AssertIsOnWorkerThread();
677 if (!aString.WasPassed()) {
678 return;
681 if (!nsJSUtils::DumpEnabled()) {
682 return;
685 NS_ConvertUTF16toUTF8 str(aString.Value());
687 MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug,
688 ("[Worker.Dump] %s", str.get()));
689 #ifdef ANDROID
690 __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", str.get());
691 #endif
692 fputs(str.get(), stdout);
693 fflush(stdout);
696 Performance* WorkerGlobalScope::GetPerformance() {
697 AssertIsOnWorkerThread();
699 if (!mPerformance) {
700 mPerformance = Performance::CreateForWorker(this);
703 return mPerformance;
706 bool WorkerGlobalScope::IsInAutomation(JSContext* aCx, JSObject* /* unused */) {
707 return GetWorkerPrivateFromContext(aCx)->IsInAutomation();
710 void WorkerGlobalScope::GetJSTestingFunctions(
711 JSContext* aCx, JS::MutableHandle<JSObject*> aFunctions, ErrorResult& aRv) {
712 JSObject* obj = js::GetTestingFunctions(aCx);
713 if (!obj) {
714 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
715 return;
718 aFunctions.set(obj);
721 already_AddRefed<Promise> WorkerGlobalScope::Fetch(
722 const RequestOrUSVString& aInput, const RequestInit& aInit,
723 CallerType aCallerType, ErrorResult& aRv) {
724 return FetchRequest(this, aInput, aInit, aCallerType, aRv);
727 already_AddRefed<IDBFactory> WorkerGlobalScope::GetIndexedDB(
728 JSContext* aCx, ErrorResult& aErrorResult) {
729 AssertIsOnWorkerThread();
731 RefPtr<IDBFactory> indexedDB = mIndexedDB;
733 if (!indexedDB) {
734 StorageAccess access = mWorkerPrivate->StorageAccess();
736 if (access == StorageAccess::eDeny) {
737 NS_WARNING("IndexedDB is not allowed in this worker!");
738 aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
739 return nullptr;
742 if (ShouldPartitionStorage(access) &&
743 !StoragePartitioningEnabled(access,
744 mWorkerPrivate->CookieJarSettings())) {
745 NS_WARNING("IndexedDB is not allowed in this worker!");
746 aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
747 return nullptr;
750 const PrincipalInfo& principalInfo =
751 mWorkerPrivate->GetEffectiveStoragePrincipalInfo();
753 auto res = IDBFactory::CreateForWorker(this, principalInfo,
754 mWorkerPrivate->WindowID());
755 if (NS_WARN_IF(res.isErr())) {
756 aErrorResult = res.unwrapErr();
757 return nullptr;
760 indexedDB = res.unwrap();
761 mIndexedDB = indexedDB;
764 return indexedDB.forget();
767 WebTaskScheduler* WorkerGlobalScope::Scheduler() {
768 mWorkerPrivate->AssertIsOnWorkerThread();
770 if (!mWebTaskScheduler) {
771 mWebTaskScheduler = WebTaskScheduler::CreateForWorker(mWorkerPrivate);
774 MOZ_ASSERT(mWebTaskScheduler);
775 return mWebTaskScheduler;
778 WebTaskScheduler* WorkerGlobalScope::GetExistingScheduler() const {
779 return mWebTaskScheduler;
782 already_AddRefed<Promise> WorkerGlobalScope::CreateImageBitmap(
783 const ImageBitmapSource& aImage, const ImageBitmapOptions& aOptions,
784 ErrorResult& aRv) {
785 return ImageBitmap::Create(this, aImage, Nothing(), aOptions, aRv);
788 already_AddRefed<Promise> WorkerGlobalScope::CreateImageBitmap(
789 const ImageBitmapSource& aImage, int32_t aSx, int32_t aSy, int32_t aSw,
790 int32_t aSh, const ImageBitmapOptions& aOptions, ErrorResult& aRv) {
791 return ImageBitmap::Create(
792 this, aImage, Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aOptions, aRv);
795 // https://html.spec.whatwg.org/#structured-cloning
796 void WorkerGlobalScope::StructuredClone(
797 JSContext* aCx, JS::Handle<JS::Value> aValue,
798 const StructuredSerializeOptions& aOptions,
799 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError) {
800 nsContentUtils::StructuredClone(aCx, this, aValue, aOptions, aRetval, aError);
803 mozilla::dom::DebuggerNotificationManager*
804 WorkerGlobalScope::GetOrCreateDebuggerNotificationManager() {
805 if (!mDebuggerNotificationManager) {
806 mDebuggerNotificationManager = new DebuggerNotificationManager(this);
809 return mDebuggerNotificationManager;
812 mozilla::dom::DebuggerNotificationManager*
813 WorkerGlobalScope::GetExistingDebuggerNotificationManager() {
814 return mDebuggerNotificationManager;
817 Maybe<EventCallbackDebuggerNotificationType>
818 WorkerGlobalScope::GetDebuggerNotificationType() const {
819 return Some(EventCallbackDebuggerNotificationType::Global);
822 RefPtr<ServiceWorkerRegistration>
823 WorkerGlobalScope::GetServiceWorkerRegistration(
824 const ServiceWorkerRegistrationDescriptor& aDescriptor) const {
825 AssertIsOnWorkerThread();
826 RefPtr<ServiceWorkerRegistration> ref;
827 ForEachEventTargetObject([&](DOMEventTargetHelper* aTarget, bool* aDoneOut) {
828 RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aTarget);
829 if (!swr || !swr->MatchesDescriptor(aDescriptor)) {
830 return;
833 ref = std::move(swr);
834 *aDoneOut = true;
836 return ref;
839 RefPtr<ServiceWorkerRegistration>
840 WorkerGlobalScope::GetOrCreateServiceWorkerRegistration(
841 const ServiceWorkerRegistrationDescriptor& aDescriptor) {
842 AssertIsOnWorkerThread();
843 RefPtr<ServiceWorkerRegistration> ref =
844 GetServiceWorkerRegistration(aDescriptor);
845 if (!ref) {
846 ref = ServiceWorkerRegistration::CreateForWorker(mWorkerPrivate, this,
847 aDescriptor);
849 return ref;
852 mozilla::dom::StorageManager* WorkerGlobalScope::GetStorageManager() {
853 return RefPtr(Navigator())->Storage();
856 // https://html.spec.whatwg.org/multipage/web-messaging.html#eligible-for-messaging
857 // * a WorkerGlobalScope object whose closing flag is false and whose worker
858 // is not a suspendable worker.
859 bool WorkerGlobalScope::IsEligibleForMessaging() {
860 return mIsEligibleForMessaging;
862 void WorkerGlobalScope::StorageAccessPermissionGranted() {
863 // Reset the IndexedDB factory.
864 mIndexedDB = nullptr;
866 // Reset DOM Cache
867 mCacheStorage = nullptr;
870 bool WorkerGlobalScope::WindowInteractionAllowed() const {
871 AssertIsOnWorkerThread();
872 return mWindowInteractionsAllowed > 0;
875 void WorkerGlobalScope::AllowWindowInteraction() {
876 AssertIsOnWorkerThread();
877 mWindowInteractionsAllowed++;
880 void WorkerGlobalScope::ConsumeWindowInteraction() {
881 AssertIsOnWorkerThread();
882 MOZ_ASSERT(mWindowInteractionsAllowed);
883 mWindowInteractionsAllowed--;
886 NS_IMPL_CYCLE_COLLECTION_INHERITED(DedicatedWorkerGlobalScope,
887 WorkerGlobalScope, mFrameRequestManager)
889 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DedicatedWorkerGlobalScope,
890 WorkerGlobalScope)
891 NS_IMPL_CYCLE_COLLECTION_TRACE_END
893 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(DedicatedWorkerGlobalScope,
894 WorkerGlobalScope)
896 DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
897 WorkerPrivate* aWorkerPrivate, UniquePtr<ClientSource> aClientSource,
898 const nsString& aName)
899 : WorkerGlobalScope(std::move(aWorkerPrivate), std::move(aClientSource)),
900 NamedWorkerGlobalScopeMixin(aName) {}
902 bool DedicatedWorkerGlobalScope::WrapGlobalObject(
903 JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
904 AssertIsOnWorkerThread();
905 MOZ_ASSERT(!mWorkerPrivate->IsSharedWorker());
907 JS::RealmOptions options;
908 mWorkerPrivate->CopyJSRealmOptions(options);
910 xpc::SetPrefableRealmOptions(options);
912 return DedicatedWorkerGlobalScope_Binding::Wrap(
913 aCx, this, this, options,
914 nsJSPrincipals::get(mWorkerPrivate->GetPrincipal()), true, aReflector);
917 void DedicatedWorkerGlobalScope::PostMessage(
918 JSContext* aCx, JS::Handle<JS::Value> aMessage,
919 const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) {
920 AssertIsOnWorkerThread();
921 mWorkerPrivate->PostMessageToParent(aCx, aMessage, aTransferable, aRv);
924 void DedicatedWorkerGlobalScope::PostMessage(
925 JSContext* aCx, JS::Handle<JS::Value> aMessage,
926 const StructuredSerializeOptions& aOptions, ErrorResult& aRv) {
927 AssertIsOnWorkerThread();
928 mWorkerPrivate->PostMessageToParent(aCx, aMessage, aOptions.mTransfer, aRv);
931 void DedicatedWorkerGlobalScope::Close() {
932 AssertIsOnWorkerThread();
933 mWorkerPrivate->CloseInternal();
936 int32_t DedicatedWorkerGlobalScope::RequestAnimationFrame(
937 FrameRequestCallback& aCallback, ErrorResult& aError) {
938 AssertIsOnWorkerThread();
940 DebuggerNotificationDispatch(this,
941 DebuggerNotificationType::RequestAnimationFrame);
943 // Ensure the worker is associated with a window.
944 if (mWorkerPrivate->WindowID() == UINT64_MAX) {
945 aError.ThrowNotSupportedError("Worker has no associated owner Window");
946 return 0;
949 if (!mVsyncChild) {
950 PBackgroundChild* bgChild = BackgroundChild::GetOrCreateForCurrentThread();
951 mVsyncChild = MakeRefPtr<VsyncWorkerChild>();
953 if (!bgChild || !mVsyncChild->Initialize(mWorkerPrivate) ||
954 !bgChild->SendPVsyncConstructor(mVsyncChild)) {
955 mVsyncChild->Destroy();
956 mVsyncChild = nullptr;
957 aError.ThrowNotSupportedError(
958 "Worker failed to register for vsync to drive event loop");
959 return 0;
963 if (!mDocListener) {
964 mDocListener = WorkerDocumentListener::Create(mWorkerPrivate);
965 if (!mDocListener) {
966 aError.ThrowNotSupportedError(
967 "Worker failed to register for document visibility events");
968 return 0;
972 int32_t handle = 0;
973 aError = mFrameRequestManager.Schedule(aCallback, &handle);
974 if (!aError.Failed() && mDocumentVisible) {
975 mVsyncChild->TryObserve();
977 return handle;
980 void DedicatedWorkerGlobalScope::CancelAnimationFrame(int32_t aHandle,
981 ErrorResult& aError) {
982 AssertIsOnWorkerThread();
984 DebuggerNotificationDispatch(this,
985 DebuggerNotificationType::CancelAnimationFrame);
987 // Ensure the worker is associated with a window.
988 if (mWorkerPrivate->WindowID() == UINT64_MAX) {
989 aError.ThrowNotSupportedError("Worker has no associated owner Window");
990 return;
993 mFrameRequestManager.Cancel(aHandle);
994 if (mVsyncChild && mFrameRequestManager.IsEmpty()) {
995 mVsyncChild->TryUnobserve();
999 void DedicatedWorkerGlobalScope::OnDocumentVisible(bool aVisible) {
1000 AssertIsOnWorkerThread();
1002 mDocumentVisible = aVisible;
1004 // We only change state immediately when we become visible. If we become
1005 // hidden, then we wait for the next vsync tick to apply that.
1006 if (aVisible && !mFrameRequestManager.IsEmpty()) {
1007 mVsyncChild->TryObserve();
1011 void DedicatedWorkerGlobalScope::OnVsync(const VsyncEvent& aVsync) {
1012 AssertIsOnWorkerThread();
1014 if (mFrameRequestManager.IsEmpty() || !mDocumentVisible) {
1015 // If we ever receive a vsync event, and there are still no callbacks to
1016 // process, or we remain hidden, we should disable observing them. By
1017 // waiting an extra tick, we ensure we minimize extra IPC for content that
1018 // does not call requestFrameAnimation directly during the callback, or
1019 // that is rapidly toggling between hidden and visible.
1020 mVsyncChild->TryUnobserve();
1021 return;
1024 nsTArray<FrameRequest> callbacks;
1025 mFrameRequestManager.Take(callbacks);
1027 RefPtr<DedicatedWorkerGlobalScope> scope(this);
1028 CallbackDebuggerNotificationGuard guard(
1029 scope, DebuggerNotificationType::RequestAnimationFrameCallback);
1031 // This is similar to what we do in nsRefreshDriver::RunFrameRequestCallbacks
1032 // and Performance::TimeStampToDOMHighResForRendering in order to have the
1033 // same behaviour for requestAnimationFrame on both the main and worker
1034 // threads.
1035 DOMHighResTimeStamp timeStamp = 0;
1036 if (!aVsync.mTime.IsNull()) {
1037 timeStamp = mWorkerPrivate->TimeStampToDOMHighRes(aVsync.mTime);
1038 // 0 is an inappropriate mixin for this this area; however CSS Animations
1039 // needs to have it's Time Reduction Logic refactored, so it's currently
1040 // only clamping for RFP mode. RFP mode gives a much lower time precision,
1041 // so we accept the security leak here for now.
1042 timeStamp = nsRFPService::ReduceTimePrecisionAsMSecsRFPOnly(
1043 timeStamp, 0, this->GetRTPCallerType());
1046 for (auto& callback : callbacks) {
1047 if (mFrameRequestManager.IsCanceled(callback.mHandle)) {
1048 continue;
1051 // MOZ_KnownLive is OK, because the stack array `callbacks` keeps the
1052 // callback alive and the mCallback strong reference can't be mutated by
1053 // the call.
1054 LogFrameRequestCallback::Run run(callback.mCallback);
1055 MOZ_KnownLive(callback.mCallback)->Call(timeStamp);
1059 SharedWorkerGlobalScope::SharedWorkerGlobalScope(
1060 WorkerPrivate* aWorkerPrivate, UniquePtr<ClientSource> aClientSource,
1061 const nsString& aName)
1062 : WorkerGlobalScope(std::move(aWorkerPrivate), std::move(aClientSource)),
1063 NamedWorkerGlobalScopeMixin(aName) {}
1065 bool SharedWorkerGlobalScope::WrapGlobalObject(
1066 JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
1067 AssertIsOnWorkerThread();
1068 MOZ_ASSERT(mWorkerPrivate->IsSharedWorker());
1070 JS::RealmOptions options;
1071 mWorkerPrivate->CopyJSRealmOptions(options);
1073 return SharedWorkerGlobalScope_Binding::Wrap(
1074 aCx, this, this, options,
1075 nsJSPrincipals::get(mWorkerPrivate->GetPrincipal()), true, aReflector);
1078 void SharedWorkerGlobalScope::Close() {
1079 AssertIsOnWorkerThread();
1080 mWorkerPrivate->CloseInternal();
1083 NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope,
1084 mClients, mExtensionBrowser, mRegistration)
1085 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerGlobalScope)
1086 NS_INTERFACE_MAP_END_INHERITING(WorkerGlobalScope)
1088 NS_IMPL_ADDREF_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope)
1089 NS_IMPL_RELEASE_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope)
1091 ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(
1092 WorkerPrivate* aWorkerPrivate, UniquePtr<ClientSource> aClientSource,
1093 const ServiceWorkerRegistrationDescriptor& aRegistrationDescriptor)
1094 : WorkerGlobalScope(std::move(aWorkerPrivate), std::move(aClientSource)),
1095 mScope(NS_ConvertUTF8toUTF16(aRegistrationDescriptor.Scope()))
1097 // Eagerly create the registration because we will need to receive
1098 // updates about the state of the registration. We can't wait until
1099 // first access to start receiving these.
1101 mRegistration(
1102 GetOrCreateServiceWorkerRegistration(aRegistrationDescriptor)) {}
1104 ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope() = default;
1106 bool ServiceWorkerGlobalScope::WrapGlobalObject(
1107 JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
1108 AssertIsOnWorkerThread();
1109 MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
1111 JS::RealmOptions options;
1112 mWorkerPrivate->CopyJSRealmOptions(options);
1114 return ServiceWorkerGlobalScope_Binding::Wrap(
1115 aCx, this, this, options,
1116 nsJSPrincipals::get(mWorkerPrivate->GetPrincipal()), true, aReflector);
1119 already_AddRefed<Clients> ServiceWorkerGlobalScope::GetClients() {
1120 if (!mClients) {
1121 mClients = new Clients(this);
1124 RefPtr<Clients> ref = mClients;
1125 return ref.forget();
1128 ServiceWorkerRegistration* ServiceWorkerGlobalScope::Registration() {
1129 return mRegistration;
1132 EventHandlerNonNull* ServiceWorkerGlobalScope::GetOnfetch() {
1133 AssertIsOnWorkerThread();
1135 return GetEventHandler(nsGkAtoms::onfetch);
1138 namespace {
1140 class ReportFetchListenerWarningRunnable final : public Runnable {
1141 const nsCString mScope;
1142 nsString mSourceSpec;
1143 uint32_t mLine;
1144 uint32_t mColumn;
1146 public:
1147 explicit ReportFetchListenerWarningRunnable(const nsString& aScope)
1148 : mozilla::Runnable("ReportFetchListenerWarningRunnable"),
1149 mScope(NS_ConvertUTF16toUTF8(aScope)) {
1150 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
1151 MOZ_ASSERT(workerPrivate);
1152 JSContext* cx = workerPrivate->GetJSContext();
1153 MOZ_ASSERT(cx);
1155 nsJSUtils::GetCallingLocation(cx, mSourceSpec, &mLine, &mColumn);
1158 NS_IMETHOD
1159 Run() override {
1160 AssertIsOnMainThread();
1162 ServiceWorkerManager::LocalizeAndReportToAllClients(
1163 mScope, "ServiceWorkerNoFetchHandler", nsTArray<nsString>{},
1164 nsIScriptError::warningFlag, mSourceSpec, u""_ns, mLine, mColumn);
1166 return NS_OK;
1170 } // anonymous namespace
1172 void ServiceWorkerGlobalScope::NoteFetchHandlerWasAdded() const {
1173 if (mWorkerPrivate->WorkerScriptExecutedSuccessfully()) {
1174 RefPtr<Runnable> r = new ReportFetchListenerWarningRunnable(mScope);
1175 mWorkerPrivate->DispatchToMainThreadForMessaging(r.forget());
1177 mWorkerPrivate->SetFetchHandlerWasAdded();
1180 void ServiceWorkerGlobalScope::SetOnfetch(
1181 mozilla::dom::EventHandlerNonNull* aCallback) {
1182 AssertIsOnWorkerThread();
1184 if (aCallback) {
1185 NoteFetchHandlerWasAdded();
1187 SetEventHandler(nsGkAtoms::onfetch, aCallback);
1190 void ServiceWorkerGlobalScope::EventListenerAdded(nsAtom* aType) {
1191 AssertIsOnWorkerThread();
1193 if (aType == nsGkAtoms::onfetch) {
1194 NoteFetchHandlerWasAdded();
1198 already_AddRefed<Promise> ServiceWorkerGlobalScope::SkipWaiting(
1199 ErrorResult& aRv) {
1200 AssertIsOnWorkerThread();
1201 MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
1203 RefPtr<Promise> promise = Promise::Create(this, aRv);
1204 if (NS_WARN_IF(aRv.Failed())) {
1205 return nullptr;
1208 using MozPromiseType =
1209 decltype(mWorkerPrivate->SetServiceWorkerSkipWaitingFlag())::element_type;
1210 auto holder = MakeRefPtr<DOMMozPromiseRequestHolder<MozPromiseType>>(this);
1212 mWorkerPrivate->SetServiceWorkerSkipWaitingFlag()
1213 ->Then(GetCurrentSerialEventTarget(), __func__,
1214 [holder, promise](const MozPromiseType::ResolveOrRejectValue&) {
1215 holder->Complete();
1216 promise->MaybeResolveWithUndefined();
1218 ->Track(*holder);
1220 return promise.forget();
1223 SafeRefPtr<extensions::ExtensionBrowser>
1224 ServiceWorkerGlobalScope::AcquireExtensionBrowser() {
1225 if (!mExtensionBrowser) {
1226 mExtensionBrowser = MakeSafeRefPtr<extensions::ExtensionBrowser>(this);
1229 return mExtensionBrowser.clonePtr();
1232 bool WorkerDebuggerGlobalScope::WrapGlobalObject(
1233 JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
1234 AssertIsOnWorkerThread();
1236 JS::RealmOptions options;
1237 mWorkerPrivate->CopyJSRealmOptions(options);
1239 return WorkerDebuggerGlobalScope_Binding::Wrap(
1240 aCx, this, this, options,
1241 nsJSPrincipals::get(mWorkerPrivate->GetPrincipal()), true, aReflector);
1244 void WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
1245 JS::MutableHandle<JSObject*> aGlobal,
1246 ErrorResult& aRv) {
1247 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
1248 if (!scope) {
1249 aRv.Throw(NS_ERROR_FAILURE);
1250 return;
1253 aGlobal.set(scope->GetWrapper());
1256 void WorkerDebuggerGlobalScope::CreateSandbox(
1257 JSContext* aCx, const nsAString& aName, JS::Handle<JSObject*> aPrototype,
1258 JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv) {
1259 AssertIsOnWorkerThread();
1261 aResult.set(nullptr);
1263 JS::Rooted<JS::Value> protoVal(aCx);
1264 protoVal.setObjectOrNull(aPrototype);
1265 JS::Rooted<JSObject*> sandbox(
1266 aCx,
1267 SimpleGlobalObject::Create(
1268 SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox, protoVal));
1270 if (!sandbox) {
1271 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
1272 return;
1275 if (!JS_WrapObject(aCx, &sandbox)) {
1276 aRv.NoteJSContextException(aCx);
1277 return;
1280 aResult.set(sandbox);
1283 void WorkerDebuggerGlobalScope::LoadSubScript(
1284 JSContext* aCx, const nsAString& aURL,
1285 const Optional<JS::Handle<JSObject*>>& aSandbox, ErrorResult& aRv) {
1286 AssertIsOnWorkerThread();
1288 Maybe<JSAutoRealm> ar;
1289 if (aSandbox.WasPassed()) {
1290 // We only care about worker debugger sandbox objects here, so
1291 // CheckedUnwrapStatic is fine.
1292 JS::Rooted<JSObject*> sandbox(aCx,
1293 js::CheckedUnwrapStatic(aSandbox.Value()));
1294 if (!sandbox || !IsWorkerDebuggerSandbox(sandbox)) {
1295 aRv.Throw(NS_ERROR_INVALID_ARG);
1296 return;
1299 ar.emplace(aCx, sandbox);
1302 nsTArray<nsString> urls;
1303 urls.AppendElement(aURL);
1304 workerinternals::Load(mWorkerPrivate, nullptr, urls, DebuggerScript, aRv);
1307 void WorkerDebuggerGlobalScope::EnterEventLoop() {
1308 // We're on the worker thread here, and WorkerPrivate's refcounting is
1309 // non-threadsafe: you can only do it on the parent thread. What that
1310 // means in practice is that we're relying on it being kept alive while
1311 // we run. Hopefully.
1312 MOZ_KnownLive(mWorkerPrivate)->EnterDebuggerEventLoop();
1315 void WorkerDebuggerGlobalScope::LeaveEventLoop() {
1316 mWorkerPrivate->LeaveDebuggerEventLoop();
1319 void WorkerDebuggerGlobalScope::PostMessage(const nsAString& aMessage) {
1320 mWorkerPrivate->PostMessageToDebugger(aMessage);
1323 void WorkerDebuggerGlobalScope::SetImmediate(Function& aHandler,
1324 ErrorResult& aRv) {
1325 mWorkerPrivate->SetDebuggerImmediate(aHandler, aRv);
1328 void WorkerDebuggerGlobalScope::ReportError(JSContext* aCx,
1329 const nsAString& aMessage) {
1330 JS::AutoFilename chars;
1331 uint32_t lineno = 0;
1332 JS::DescribeScriptedCaller(aCx, &chars, &lineno);
1333 nsString filename(NS_ConvertUTF8toUTF16(chars.get()));
1334 mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage);
1337 void WorkerDebuggerGlobalScope::RetrieveConsoleEvents(
1338 JSContext* aCx, nsTArray<JS::Value>& aEvents, ErrorResult& aRv) {
1339 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
1340 if (!scope) {
1341 aRv.Throw(NS_ERROR_FAILURE);
1342 return;
1345 RefPtr<Console> console = scope->GetConsole(aRv);
1346 if (NS_WARN_IF(aRv.Failed())) {
1347 return;
1350 console->RetrieveConsoleEvents(aCx, aEvents, aRv);
1353 void WorkerDebuggerGlobalScope::ClearConsoleEvents(JSContext* aCx,
1354 ErrorResult& aRv) {
1355 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
1356 if (!scope) {
1357 aRv.Throw(NS_ERROR_FAILURE);
1358 return;
1361 RefPtr<Console> console = scope->GetConsoleIfExists();
1362 if (console) {
1363 console->ClearStorage();
1367 void WorkerDebuggerGlobalScope::SetConsoleEventHandler(JSContext* aCx,
1368 AnyCallback* aHandler,
1369 ErrorResult& aRv) {
1370 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
1371 if (!scope) {
1372 aRv.Throw(NS_ERROR_FAILURE);
1373 return;
1376 RefPtr<Console> console = scope->GetConsole(aRv);
1377 if (NS_WARN_IF(aRv.Failed())) {
1378 return;
1381 console->SetConsoleEventHandler(aHandler);
1384 void WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
1385 const Optional<nsAString>& aString) const {
1386 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
1387 if (scope) {
1388 scope->Dump(aString);
1392 bool IsWorkerGlobal(JSObject* object) {
1393 return IS_INSTANCE_OF(WorkerGlobalScope, object);
1396 bool IsWorkerDebuggerGlobal(JSObject* object) {
1397 return IS_INSTANCE_OF(WorkerDebuggerGlobalScope, object);
1400 bool IsWorkerDebuggerSandbox(JSObject* object) {
1401 return SimpleGlobalObject::SimpleGlobalType(object) ==
1402 SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox;
1405 } // namespace mozilla::dom