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"
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"
22 #include "js/Wrapper.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"
97 #include "nsContentUtils.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"
117 #include "xpcpublic.h"
120 # include <android/log.h>
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");
140 #define LOG(args) MOZ_LOG(sWorkerScopeLog, LogLevel::Debug, args);
142 class WorkerScriptTimeoutHandler final
: public ScriptTimeoutHandler
{
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
;
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
) {
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
)) {
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
);
249 mWorkerPrivate
->AssertIsOnWorkerThread();
250 mWorkerThreadUsedOnlyForAssert
= PR_GetCurrentThread();
252 MOZ_ASSERT(mClientSource
);
254 MOZ_DIAGNOSTIC_ASSERT(
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();
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
);
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
),
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(),
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();
386 mConsole
= Console::Create(mWorkerPrivate
->GetJSContext(), nullptr, aRv
);
387 if (NS_WARN_IF(aRv
.Failed())) {
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));
445 void WorkerGlobalScope::NoteShuttingDown() {
446 MOZ_ASSERT(IsDying());
447 LOG(("WorkerGlobalScope::NoteShuttingDown [%p]", this));
450 mNavigator
->Invalidate();
451 mNavigator
= nullptr;
455 Crypto
* WorkerGlobalScope::GetCrypto(ErrorResult
& aError
) {
456 AssertIsOnWorkerThread();
459 mCrypto
= new Crypto(this);
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
;
475 bool WorkerGlobalScope::IsSecureContext() const {
476 bool globalSecure
= JS::GetIsSecureContext(
477 js::GetNonCCWObjectRealm(GetWrapperPreserveColor()));
478 MOZ_ASSERT(globalSecure
== mWorkerPrivate
->IsSecureContext());
482 already_AddRefed
<WorkerLocation
> WorkerGlobalScope::Location() {
483 AssertIsOnWorkerThread();
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();
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()
508 AssertIsOnWorkerThread();
510 RefPtr
<WorkerNavigator
> navigator
= mNavigator
;
511 return navigator
.forget();
514 FontFaceSet
* WorkerGlobalScope::GetFonts(ErrorResult
& aRv
) {
515 AssertIsOnWorkerThread();
518 mFontFaceSet
= FontFaceSet::CreateForWorker(this, mWorkerPrivate
);
519 if (MOZ_UNLIKELY(!mFontFaceSet
)) {
520 aRv
.ThrowInvalidStateError("Couldn't acquire worker reference");
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();
540 elm
->SetEventHandler(aHandler
);
544 void WorkerGlobalScope::ImportScripts(JSContext
* aCx
,
545 const Sequence
<nsString
>& aScriptURLs
,
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
) {
563 std::min(size_t(128), scriptUrl
.Length())),
567 workerinternals::Load(mWorkerPrivate
, std::move(stack
), aScriptURLs
,
572 int32_t WorkerGlobalScope::SetTimeout(JSContext
* aCx
, Function
& aHandler
,
573 const int32_t aTimeout
,
574 const Sequence
<JS::Value
>& aArguments
,
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 */,
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
,
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 */,
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
);
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
,
644 AssertIsOnWorkerThread();
646 DebuggerNotificationDispatch(
647 this, aIsInterval
? DebuggerNotificationType::SetInterval
648 : DebuggerNotificationType::SetTimeout
);
650 bool allowEval
= false;
652 CSPEvalChecker::CheckForWorker(aCx
, mWorkerPrivate
, aHandler
, &allowEval
);
653 if (NS_WARN_IF(aRv
.Failed()) || !allowEval
) {
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()) {
681 if (!nsJSUtils::DumpEnabled()) {
685 NS_ConvertUTF16toUTF8
str(aString
.Value());
687 MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug
,
688 ("[Worker.Dump] %s", str
.get()));
690 __android_log_print(ANDROID_LOG_INFO
, "Gecko", "%s", str
.get());
692 fputs(str
.get(), stdout
);
696 Performance
* WorkerGlobalScope::GetPerformance() {
697 AssertIsOnWorkerThread();
700 mPerformance
= Performance::CreateForWorker(this);
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
);
714 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
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
;
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
;
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
;
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();
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
,
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
)) {
833 ref
= std::move(swr
);
839 RefPtr
<ServiceWorkerRegistration
>
840 WorkerGlobalScope::GetOrCreateServiceWorkerRegistration(
841 const ServiceWorkerRegistrationDescriptor
& aDescriptor
) {
842 AssertIsOnWorkerThread();
843 RefPtr
<ServiceWorkerRegistration
> ref
=
844 GetServiceWorkerRegistration(aDescriptor
);
846 ref
= ServiceWorkerRegistration::CreateForWorker(mWorkerPrivate
, this,
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;
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
,
891 NS_IMPL_CYCLE_COLLECTION_TRACE_END
893 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(DedicatedWorkerGlobalScope
,
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");
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");
964 mDocListener
= WorkerDocumentListener::Create(mWorkerPrivate
);
966 aError
.ThrowNotSupportedError(
967 "Worker failed to register for document visibility events");
973 aError
= mFrameRequestManager
.Schedule(aCallback
, &handle
);
974 if (!aError
.Failed() && mDocumentVisible
) {
975 mVsyncChild
->TryObserve();
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");
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();
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
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
)) {
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
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.
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() {
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
);
1140 class ReportFetchListenerWarningRunnable final
: public Runnable
{
1141 const nsCString mScope
;
1142 nsString mSourceSpec
;
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();
1155 nsJSUtils::GetCallingLocation(cx
, mSourceSpec
, &mLine
, &mColumn
);
1160 AssertIsOnMainThread();
1162 ServiceWorkerManager::LocalizeAndReportToAllClients(
1163 mScope
, "ServiceWorkerNoFetchHandler", nsTArray
<nsString
>{},
1164 nsIScriptError::warningFlag
, mSourceSpec
, u
""_ns
, mLine
, mColumn
);
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();
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(
1200 AssertIsOnWorkerThread();
1201 MOZ_ASSERT(mWorkerPrivate
->IsServiceWorker());
1203 RefPtr
<Promise
> promise
= Promise::Create(this, aRv
);
1204 if (NS_WARN_IF(aRv
.Failed())) {
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
&) {
1216 promise
->MaybeResolveWithUndefined();
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
,
1247 WorkerGlobalScope
* scope
= mWorkerPrivate
->GetOrCreateGlobalScope(aCx
);
1249 aRv
.Throw(NS_ERROR_FAILURE
);
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(
1267 SimpleGlobalObject::Create(
1268 SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox
, protoVal
));
1271 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
1275 if (!JS_WrapObject(aCx
, &sandbox
)) {
1276 aRv
.NoteJSContextException(aCx
);
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
);
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
,
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
);
1341 aRv
.Throw(NS_ERROR_FAILURE
);
1345 RefPtr
<Console
> console
= scope
->GetConsole(aRv
);
1346 if (NS_WARN_IF(aRv
.Failed())) {
1350 console
->RetrieveConsoleEvents(aCx
, aEvents
, aRv
);
1353 void WorkerDebuggerGlobalScope::ClearConsoleEvents(JSContext
* aCx
,
1355 WorkerGlobalScope
* scope
= mWorkerPrivate
->GetOrCreateGlobalScope(aCx
);
1357 aRv
.Throw(NS_ERROR_FAILURE
);
1361 RefPtr
<Console
> console
= scope
->GetConsoleIfExists();
1363 console
->ClearStorage();
1367 void WorkerDebuggerGlobalScope::SetConsoleEventHandler(JSContext
* aCx
,
1368 AnyCallback
* aHandler
,
1370 WorkerGlobalScope
* scope
= mWorkerPrivate
->GetOrCreateGlobalScope(aCx
);
1372 aRv
.Throw(NS_ERROR_FAILURE
);
1376 RefPtr
<Console
> console
= scope
->GetConsole(aRv
);
1377 if (NS_WARN_IF(aRv
.Failed())) {
1381 console
->SetConsoleEventHandler(aHandler
);
1384 void WorkerDebuggerGlobalScope::Dump(JSContext
* aCx
,
1385 const Optional
<nsAString
>& aString
) const {
1386 WorkerGlobalScope
* scope
= mWorkerPrivate
->GetOrCreateGlobalScope(aCx
);
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