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 "WorkerScope.h"
10 #include "jsfriendapi.h"
11 #include "mozilla/EventListenerManager.h"
12 #include "mozilla/dom/BindingDeclarations.h"
13 #include "mozilla/dom/Clients.h"
14 #include "mozilla/dom/ClientState.h"
15 #include "mozilla/dom/Console.h"
16 #include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
17 #include "mozilla/dom/DOMPrefs.h"
18 #include "mozilla/dom/Fetch.h"
19 #include "mozilla/dom/FunctionBinding.h"
20 #include "mozilla/dom/IDBFactory.h"
21 #include "mozilla/dom/ImageBitmap.h"
22 #include "mozilla/dom/ImageBitmapBinding.h"
23 #include "mozilla/dom/Performance.h"
24 #include "mozilla/dom/Promise.h"
25 #include "mozilla/dom/PromiseWorkerProxy.h"
26 #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
27 #include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
28 #include "mozilla/dom/SimpleGlobalObject.h"
29 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
30 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
31 #include "mozilla/dom/WorkerLocation.h"
32 #include "mozilla/dom/WorkerNavigator.h"
33 #include "mozilla/dom/cache/CacheStorage.h"
34 #include "mozilla/StaticPrefs.h"
35 #include "mozilla/StorageAccess.h"
36 #include "nsServiceManagerUtils.h"
38 #include "mozilla/dom/Document.h"
39 #include "nsIServiceWorkerManager.h"
40 #include "nsIScriptError.h"
41 #include "nsIScriptTimeoutHandler.h"
44 # include <android/log.h>
48 #include "Principal.h"
49 #include "RuntimeService.h"
50 #include "ScriptLoader.h"
51 #include "WorkerPrivate.h"
52 #include "WorkerRunnable.h"
53 #include "mozilla/dom/ServiceWorkerManager.h"
54 #include "mozilla/dom/ServiceWorkerRegistration.h"
60 extern already_AddRefed
<nsIScriptTimeoutHandler
> NS_CreateJSTimeoutHandler(
61 JSContext
* aCx
, mozilla::dom::WorkerPrivate
* aWorkerPrivate
,
62 mozilla::dom::Function
& aFunction
,
63 const mozilla::dom::Sequence
<JS::Value
>& aArguments
,
64 mozilla::ErrorResult
& aError
);
66 extern already_AddRefed
<nsIScriptTimeoutHandler
> NS_CreateJSTimeoutHandler(
67 JSContext
* aCx
, mozilla::dom::WorkerPrivate
* aWorkerPrivate
,
68 const nsAString
& aExpression
, mozilla::ErrorResult
& aRv
);
73 using mozilla::dom::cache::CacheStorage
;
74 using mozilla::ipc::PrincipalInfo
;
76 WorkerGlobalScope::WorkerGlobalScope(WorkerPrivate
* aWorkerPrivate
)
77 : mSerialEventTarget(aWorkerPrivate
->HybridEventTarget()),
78 mWindowInteractionsAllowed(0),
79 mWorkerPrivate(aWorkerPrivate
) {
80 mWorkerPrivate
->AssertIsOnWorkerThread();
82 // We should always have an event target when the global is created.
83 MOZ_DIAGNOSTIC_ASSERT(mSerialEventTarget
);
85 // In workers, each DETH must have an owner. Because the global scope doesn't
86 // have one, let's set it as owner of itself.
87 BindToOwner(static_cast<nsIGlobalObject
*>(this));
90 WorkerGlobalScope::~WorkerGlobalScope() {
91 mWorkerPrivate
->AssertIsOnWorkerThread();
94 NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerGlobalScope
)
96 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope
,
98 tmp
->mWorkerPrivate
->AssertIsOnWorkerThread();
99 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole
)
100 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto
)
101 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance
)
102 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation
)
103 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator
)
104 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB
)
105 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage
)
106 tmp
->TraverseHostObjectURIs(cb
);
107 tmp
->mWorkerPrivate
->TraverseTimeouts(cb
);
108 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
110 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope
,
111 DOMEventTargetHelper
)
112 tmp
->mWorkerPrivate
->AssertIsOnWorkerThread();
113 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole
)
114 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto
)
115 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance
)
116 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation
)
117 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator
)
118 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB
)
119 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage
)
120 tmp
->UnlinkHostObjectURIs();
121 tmp
->mWorkerPrivate
->UnlinkTimeouts();
122 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
124 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScope
,
125 DOMEventTargetHelper
)
126 tmp
->mWorkerPrivate
->AssertIsOnWorkerThread();
127 NS_IMPL_CYCLE_COLLECTION_TRACE_END
129 NS_IMPL_ADDREF_INHERITED(WorkerGlobalScope
, DOMEventTargetHelper
)
130 NS_IMPL_RELEASE_INHERITED(WorkerGlobalScope
, DOMEventTargetHelper
)
132 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerGlobalScope
)
133 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject
)
134 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
135 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
137 JSObject
* WorkerGlobalScope::WrapObject(JSContext
* aCx
,
138 JS::Handle
<JSObject
*> aGivenProto
) {
139 MOZ_CRASH("We should never get here!");
142 void WorkerGlobalScope::NoteTerminating() {
143 DisconnectEventTargetObjects();
147 already_AddRefed
<Console
> WorkerGlobalScope::GetConsole(ErrorResult
& aRv
) {
148 mWorkerPrivate
->AssertIsOnWorkerThread();
151 mConsole
= Console::Create(mWorkerPrivate
->GetJSContext(), nullptr, aRv
);
152 if (NS_WARN_IF(aRv
.Failed())) {
157 RefPtr
<Console
> console
= mConsole
;
158 return console
.forget();
161 Crypto
* WorkerGlobalScope::GetCrypto(ErrorResult
& aError
) {
162 mWorkerPrivate
->AssertIsOnWorkerThread();
165 mCrypto
= new Crypto(this);
171 already_AddRefed
<CacheStorage
> WorkerGlobalScope::GetCaches(ErrorResult
& aRv
) {
172 if (!mCacheStorage
) {
173 MOZ_ASSERT(mWorkerPrivate
);
174 mCacheStorage
= CacheStorage::CreateOnWorker(cache::DEFAULT_NAMESPACE
, this,
175 mWorkerPrivate
, aRv
);
178 RefPtr
<CacheStorage
> ref
= mCacheStorage
;
182 bool WorkerGlobalScope::IsSecureContext() const {
183 bool globalSecure
= JS::GetIsSecureContext(
184 js::GetNonCCWObjectRealm(GetWrapperPreserveColor()));
185 MOZ_ASSERT(globalSecure
== mWorkerPrivate
->IsSecureContext());
189 already_AddRefed
<WorkerLocation
> WorkerGlobalScope::Location() {
190 mWorkerPrivate
->AssertIsOnWorkerThread();
193 WorkerPrivate::LocationInfo
& info
= mWorkerPrivate
->GetLocationInfo();
195 mLocation
= WorkerLocation::Create(info
);
196 MOZ_ASSERT(mLocation
);
199 RefPtr
<WorkerLocation
> location
= mLocation
;
200 return location
.forget();
203 already_AddRefed
<WorkerNavigator
> WorkerGlobalScope::Navigator() {
204 mWorkerPrivate
->AssertIsOnWorkerThread();
207 mNavigator
= WorkerNavigator::Create(mWorkerPrivate
->OnLine());
208 MOZ_ASSERT(mNavigator
);
211 RefPtr
<WorkerNavigator
> navigator
= mNavigator
;
212 return navigator
.forget();
215 already_AddRefed
<WorkerNavigator
> WorkerGlobalScope::GetExistingNavigator()
217 mWorkerPrivate
->AssertIsOnWorkerThread();
219 RefPtr
<WorkerNavigator
> navigator
= mNavigator
;
220 return navigator
.forget();
223 OnErrorEventHandlerNonNull
* WorkerGlobalScope::GetOnerror() {
224 mWorkerPrivate
->AssertIsOnWorkerThread();
226 EventListenerManager
* elm
= GetExistingListenerManager();
227 return elm
? elm
->GetOnErrorEventHandler() : nullptr;
230 void WorkerGlobalScope::SetOnerror(OnErrorEventHandlerNonNull
* aHandler
) {
231 mWorkerPrivate
->AssertIsOnWorkerThread();
233 EventListenerManager
* elm
= GetOrCreateListenerManager();
235 elm
->SetEventHandler(aHandler
);
239 void WorkerGlobalScope::ImportScripts(JSContext
* aCx
,
240 const Sequence
<nsString
>& aScriptURLs
,
242 mWorkerPrivate
->AssertIsOnWorkerThread();
244 UniquePtr
<SerializedStackHolder
> stack
;
245 if (mWorkerPrivate
->IsWatchedByDevtools()) {
246 stack
= GetCurrentStackForNetMonitor(aCx
);
249 workerinternals::Load(mWorkerPrivate
, std::move(stack
), aScriptURLs
,
253 int32_t WorkerGlobalScope::SetTimeout(JSContext
* aCx
, Function
& aHandler
,
254 const int32_t aTimeout
,
255 const Sequence
<JS::Value
>& aArguments
,
257 mWorkerPrivate
->AssertIsOnWorkerThread();
259 nsCOMPtr
<nsIScriptTimeoutHandler
> handler
=
260 NS_CreateJSTimeoutHandler(aCx
, mWorkerPrivate
, aHandler
, aArguments
, aRv
);
265 return mWorkerPrivate
->SetTimeout(aCx
, handler
, aTimeout
, false, aRv
);
268 int32_t WorkerGlobalScope::SetTimeout(JSContext
* aCx
, const nsAString
& aHandler
,
269 const int32_t aTimeout
,
270 const Sequence
<JS::Value
>& /* unused */,
272 mWorkerPrivate
->AssertIsOnWorkerThread();
274 nsCOMPtr
<nsIScriptTimeoutHandler
> handler
=
275 NS_CreateJSTimeoutHandler(aCx
, mWorkerPrivate
, aHandler
, aRv
);
280 return mWorkerPrivate
->SetTimeout(aCx
, handler
, aTimeout
, false, aRv
);
283 void WorkerGlobalScope::ClearTimeout(int32_t aHandle
) {
284 mWorkerPrivate
->AssertIsOnWorkerThread();
285 mWorkerPrivate
->ClearTimeout(aHandle
);
288 int32_t WorkerGlobalScope::SetInterval(JSContext
* aCx
, Function
& aHandler
,
289 const int32_t aTimeout
,
290 const Sequence
<JS::Value
>& aArguments
,
292 mWorkerPrivate
->AssertIsOnWorkerThread();
294 nsCOMPtr
<nsIScriptTimeoutHandler
> handler
=
295 NS_CreateJSTimeoutHandler(aCx
, mWorkerPrivate
, aHandler
, aArguments
, aRv
);
296 if (NS_WARN_IF(aRv
.Failed())) {
300 return mWorkerPrivate
->SetTimeout(aCx
, handler
, aTimeout
, true, aRv
);
303 int32_t WorkerGlobalScope::SetInterval(JSContext
* aCx
,
304 const nsAString
& aHandler
,
305 const int32_t aTimeout
,
306 const Sequence
<JS::Value
>& /* unused */,
308 mWorkerPrivate
->AssertIsOnWorkerThread();
310 Sequence
<JS::Value
> dummy
;
312 nsCOMPtr
<nsIScriptTimeoutHandler
> handler
=
313 NS_CreateJSTimeoutHandler(aCx
, mWorkerPrivate
, aHandler
, aRv
);
314 if (NS_WARN_IF(aRv
.Failed())) {
318 return mWorkerPrivate
->SetTimeout(aCx
, handler
, aTimeout
, true, aRv
);
321 void WorkerGlobalScope::ClearInterval(int32_t aHandle
) {
322 mWorkerPrivate
->AssertIsOnWorkerThread();
323 mWorkerPrivate
->ClearTimeout(aHandle
);
326 void WorkerGlobalScope::GetOrigin(nsAString
& aOrigin
) const {
327 mWorkerPrivate
->AssertIsOnWorkerThread();
328 aOrigin
= mWorkerPrivate
->Origin();
331 void WorkerGlobalScope::Atob(const nsAString
& aAtob
, nsAString
& aOutput
,
332 ErrorResult
& aRv
) const {
333 mWorkerPrivate
->AssertIsOnWorkerThread();
334 aRv
= nsContentUtils::Atob(aAtob
, aOutput
);
337 void WorkerGlobalScope::Btoa(const nsAString
& aBtoa
, nsAString
& aOutput
,
338 ErrorResult
& aRv
) const {
339 mWorkerPrivate
->AssertIsOnWorkerThread();
340 aRv
= nsContentUtils::Btoa(aBtoa
, aOutput
);
343 void WorkerGlobalScope::Dump(const Optional
<nsAString
>& aString
) const {
344 mWorkerPrivate
->AssertIsOnWorkerThread();
346 if (!aString
.WasPassed()) {
350 #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
351 if (!DOMPrefs::DumpEnabled()) {
356 NS_ConvertUTF16toUTF8
str(aString
.Value());
358 MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug
,
359 ("[Worker.Dump] %s", str
.get()));
361 __android_log_print(ANDROID_LOG_INFO
, "Gecko", "%s", str
.get());
363 fputs(str
.get(), stdout
);
367 Performance
* WorkerGlobalScope::GetPerformance() {
368 mWorkerPrivate
->AssertIsOnWorkerThread();
371 mPerformance
= Performance::CreateForWorker(mWorkerPrivate
);
377 bool WorkerGlobalScope::IsInAutomation(JSContext
* aCx
, JSObject
* /* unused */) {
378 return GetWorkerPrivateFromContext(aCx
)->IsInAutomation();
381 void WorkerGlobalScope::GetJSTestingFunctions(
382 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aFunctions
, ErrorResult
& aRv
) {
383 JSObject
* obj
= js::GetTestingFunctions(aCx
);
385 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
392 already_AddRefed
<Promise
> WorkerGlobalScope::Fetch(
393 const RequestOrUSVString
& aInput
, const RequestInit
& aInit
,
394 CallerType aCallerType
, ErrorResult
& aRv
) {
395 return FetchRequest(this, aInput
, aInit
, aCallerType
, aRv
);
398 already_AddRefed
<IDBFactory
> WorkerGlobalScope::GetIndexedDB(
399 ErrorResult
& aErrorResult
) {
400 mWorkerPrivate
->AssertIsOnWorkerThread();
402 RefPtr
<IDBFactory
> indexedDB
= mIndexedDB
;
405 StorageAccess access
= mWorkerPrivate
->StorageAccess();
407 if (access
== StorageAccess::eDeny
) {
408 NS_WARNING("IndexedDB is not allowed in this worker!");
409 aErrorResult
= NS_ERROR_DOM_SECURITY_ERR
;
413 if (ShouldPartitionStorage(access
) &&
414 !StoragePartitioningEnabled(access
, mWorkerPrivate
->CookieSettings())) {
415 NS_WARNING("IndexedDB is not allowed in this worker!");
416 aErrorResult
= NS_ERROR_DOM_SECURITY_ERR
;
420 const PrincipalInfo
& principalInfo
=
421 mWorkerPrivate
->GetEffectiveStoragePrincipalInfo();
423 nsresult rv
= IDBFactory::CreateForWorker(this, principalInfo
,
424 mWorkerPrivate
->WindowID(),
425 getter_AddRefs(indexedDB
));
426 if (NS_WARN_IF(NS_FAILED(rv
))) {
431 mIndexedDB
= indexedDB
;
434 return indexedDB
.forget();
437 already_AddRefed
<Promise
> WorkerGlobalScope::CreateImageBitmap(
438 JSContext
* aCx
, const ImageBitmapSource
& aImage
, ErrorResult
& aRv
) {
439 return ImageBitmap::Create(this, aImage
, Nothing(), aRv
);
442 already_AddRefed
<Promise
> WorkerGlobalScope::CreateImageBitmap(
443 JSContext
* aCx
, const ImageBitmapSource
& aImage
, int32_t aSx
, int32_t aSy
,
444 int32_t aSw
, int32_t aSh
, ErrorResult
& aRv
) {
445 return ImageBitmap::Create(this, aImage
,
446 Some(gfx::IntRect(aSx
, aSy
, aSw
, aSh
)), aRv
);
449 nsresult
WorkerGlobalScope::Dispatch(
450 TaskCategory aCategory
, already_AddRefed
<nsIRunnable
>&& aRunnable
) {
451 return EventTargetFor(aCategory
)->Dispatch(std::move(aRunnable
),
455 nsISerialEventTarget
* WorkerGlobalScope::EventTargetFor(
456 TaskCategory aCategory
) const {
457 return mSerialEventTarget
;
460 AbstractThread
* WorkerGlobalScope::AbstractMainThreadFor(
461 TaskCategory aCategory
) {
462 MOZ_CRASH("AbstractMainThreadFor not supported for workers.");
465 Maybe
<ClientInfo
> WorkerGlobalScope::GetClientInfo() const {
466 return mWorkerPrivate
->GetClientInfo();
469 Maybe
<ClientState
> WorkerGlobalScope::GetClientState() const {
470 Maybe
<ClientState
> state
;
471 state
.emplace(mWorkerPrivate
->GetClientState());
475 Maybe
<ServiceWorkerDescriptor
> WorkerGlobalScope::GetController() const {
476 return mWorkerPrivate
->GetController();
479 RefPtr
<mozilla::dom::ServiceWorkerRegistration
>
480 WorkerGlobalScope::GetServiceWorkerRegistration(
481 const ServiceWorkerRegistrationDescriptor
& aDescriptor
) const {
482 mWorkerPrivate
->AssertIsOnWorkerThread();
483 RefPtr
<ServiceWorkerRegistration
> ref
;
484 ForEachEventTargetObject([&](DOMEventTargetHelper
* aTarget
, bool* aDoneOut
) {
485 RefPtr
<ServiceWorkerRegistration
> swr
= do_QueryObject(aTarget
);
486 if (!swr
|| !swr
->MatchesDescriptor(aDescriptor
)) {
496 RefPtr
<ServiceWorkerRegistration
>
497 WorkerGlobalScope::GetOrCreateServiceWorkerRegistration(
498 const ServiceWorkerRegistrationDescriptor
& aDescriptor
) {
499 mWorkerPrivate
->AssertIsOnWorkerThread();
500 RefPtr
<ServiceWorkerRegistration
> ref
=
501 GetServiceWorkerRegistration(aDescriptor
);
503 ref
= ServiceWorkerRegistration::CreateForWorker(mWorkerPrivate
, this,
509 void WorkerGlobalScope::FirstPartyStorageAccessGranted() {
510 // Reset the IndexedDB factory.
511 mIndexedDB
= nullptr;
514 mCacheStorage
= nullptr;
517 DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
518 WorkerPrivate
* aWorkerPrivate
, const nsString
& aName
)
519 : WorkerGlobalScope(aWorkerPrivate
), mName(aName
) {}
521 bool DedicatedWorkerGlobalScope::WrapGlobalObject(
522 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aReflector
) {
523 mWorkerPrivate
->AssertIsOnWorkerThread();
524 MOZ_ASSERT(!mWorkerPrivate
->IsSharedWorker());
526 JS::RealmOptions options
;
527 mWorkerPrivate
->CopyJSRealmOptions(options
);
529 const bool usesSystemPrincipal
= mWorkerPrivate
->UsesSystemPrincipal();
531 // Note that xpc::ShouldDiscardSystemSource() and
532 // xpc::ExtraWarningsForSystemJS() read prefs that are cached on the main
533 // thread. This is benignly racey.
534 const bool discardSource
=
535 usesSystemPrincipal
&& xpc::ShouldDiscardSystemSource();
536 const bool extraWarnings
=
537 usesSystemPrincipal
&& xpc::ExtraWarningsForSystemJS();
539 JS::RealmBehaviors
& behaviors
= options
.behaviors();
540 behaviors
.setDiscardSource(discardSource
)
541 .extraWarningsOverride()
544 xpc::SetPrefableRealmOptions(options
);
546 return DedicatedWorkerGlobalScope_Binding::Wrap(
547 aCx
, this, this, options
, GetWorkerPrincipal(), true, aReflector
);
550 void DedicatedWorkerGlobalScope::PostMessage(
551 JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
552 const Sequence
<JSObject
*>& aTransferable
, ErrorResult
& aRv
) {
553 mWorkerPrivate
->AssertIsOnWorkerThread();
554 mWorkerPrivate
->PostMessageToParent(aCx
, aMessage
, aTransferable
, aRv
);
557 void DedicatedWorkerGlobalScope::PostMessage(JSContext
* aCx
,
558 JS::Handle
<JS::Value
> aMessage
,
559 const PostMessageOptions
& aOptions
,
561 mWorkerPrivate
->AssertIsOnWorkerThread();
562 mWorkerPrivate
->PostMessageToParent(aCx
, aMessage
, aOptions
.mTransfer
, aRv
);
565 void DedicatedWorkerGlobalScope::Close() {
566 mWorkerPrivate
->AssertIsOnWorkerThread();
567 mWorkerPrivate
->CloseInternal();
570 SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate
* aWorkerPrivate
,
571 const nsString
& aName
)
572 : WorkerGlobalScope(aWorkerPrivate
), mName(aName
) {}
574 bool SharedWorkerGlobalScope::WrapGlobalObject(
575 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aReflector
) {
576 mWorkerPrivate
->AssertIsOnWorkerThread();
577 MOZ_ASSERT(mWorkerPrivate
->IsSharedWorker());
579 JS::RealmOptions options
;
580 mWorkerPrivate
->CopyJSRealmOptions(options
);
582 return SharedWorkerGlobalScope_Binding::Wrap(
583 aCx
, this, this, options
, GetWorkerPrincipal(), true, aReflector
);
586 void SharedWorkerGlobalScope::Close() {
587 mWorkerPrivate
->AssertIsOnWorkerThread();
588 mWorkerPrivate
->CloseInternal();
591 NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope
, WorkerGlobalScope
,
592 mClients
, mRegistration
)
593 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerGlobalScope
)
594 NS_INTERFACE_MAP_END_INHERITING(WorkerGlobalScope
)
596 NS_IMPL_ADDREF_INHERITED(ServiceWorkerGlobalScope
, WorkerGlobalScope
)
597 NS_IMPL_RELEASE_INHERITED(ServiceWorkerGlobalScope
, WorkerGlobalScope
)
599 ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(
600 WorkerPrivate
* aWorkerPrivate
,
601 const ServiceWorkerRegistrationDescriptor
& aRegistrationDescriptor
)
602 : WorkerGlobalScope(aWorkerPrivate
),
603 mScope(NS_ConvertUTF8toUTF16(aRegistrationDescriptor
.Scope()))
605 // Eagerly create the registration because we will need to receive updates
606 // about the state of the registration. We can't wait until first access
607 // to start receiving these.
610 GetOrCreateServiceWorkerRegistration(aRegistrationDescriptor
)) {}
612 ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope() {}
614 bool ServiceWorkerGlobalScope::WrapGlobalObject(
615 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aReflector
) {
616 mWorkerPrivate
->AssertIsOnWorkerThread();
617 MOZ_ASSERT(mWorkerPrivate
->IsServiceWorker());
619 JS::RealmOptions options
;
620 mWorkerPrivate
->CopyJSRealmOptions(options
);
622 return ServiceWorkerGlobalScope_Binding::Wrap(
623 aCx
, this, this, options
, GetWorkerPrincipal(), true, aReflector
);
626 already_AddRefed
<Clients
> ServiceWorkerGlobalScope::GetClients() {
628 mClients
= new Clients(this);
631 RefPtr
<Clients
> ref
= mClients
;
635 ServiceWorkerRegistration
* ServiceWorkerGlobalScope::Registration() {
636 return mRegistration
;
639 EventHandlerNonNull
* ServiceWorkerGlobalScope::GetOnfetch() {
640 MOZ_ASSERT(mWorkerPrivate
);
641 mWorkerPrivate
->AssertIsOnWorkerThread();
643 return GetEventHandler(nsGkAtoms::onfetch
);
648 class ReportFetchListenerWarningRunnable final
: public Runnable
{
649 const nsCString mScope
;
650 nsCString mSourceSpec
;
655 explicit ReportFetchListenerWarningRunnable(const nsString
& aScope
)
656 : mozilla::Runnable("ReportFetchListenerWarningRunnable"),
657 mScope(NS_ConvertUTF16toUTF8(aScope
)) {
658 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
659 MOZ_ASSERT(workerPrivate
);
660 JSContext
* cx
= workerPrivate
->GetJSContext();
663 nsJSUtils::GetCallingLocation(cx
, mSourceSpec
, &mLine
, &mColumn
);
668 AssertIsOnMainThread();
670 ServiceWorkerManager::LocalizeAndReportToAllClients(
671 mScope
, "ServiceWorkerNoFetchHandler", nsTArray
<nsString
>{},
672 nsIScriptError::warningFlag
, NS_ConvertUTF8toUTF16(mSourceSpec
),
673 EmptyString(), mLine
, mColumn
);
679 } // anonymous namespace
681 void ServiceWorkerGlobalScope::SetOnfetch(
682 mozilla::dom::EventHandlerNonNull
* aCallback
) {
683 MOZ_ASSERT(mWorkerPrivate
);
684 mWorkerPrivate
->AssertIsOnWorkerThread();
687 if (mWorkerPrivate
->WorkerScriptExecutedSuccessfully()) {
688 RefPtr
<Runnable
> r
= new ReportFetchListenerWarningRunnable(mScope
);
689 mWorkerPrivate
->DispatchToMainThreadForMessaging(r
.forget());
691 mWorkerPrivate
->SetFetchHandlerWasAdded();
693 SetEventHandler(nsGkAtoms::onfetch
, aCallback
);
696 void ServiceWorkerGlobalScope::EventListenerAdded(nsAtom
* aType
) {
697 MOZ_ASSERT(mWorkerPrivate
);
698 mWorkerPrivate
->AssertIsOnWorkerThread();
700 if (aType
!= nsGkAtoms::onfetch
) {
704 if (mWorkerPrivate
->WorkerScriptExecutedSuccessfully()) {
705 RefPtr
<Runnable
> r
= new ReportFetchListenerWarningRunnable(mScope
);
706 mWorkerPrivate
->DispatchToMainThreadForMessaging(r
.forget());
709 mWorkerPrivate
->SetFetchHandlerWasAdded();
714 class SkipWaitingResultRunnable final
: public WorkerRunnable
{
715 RefPtr
<PromiseWorkerProxy
> mPromiseProxy
;
718 SkipWaitingResultRunnable(WorkerPrivate
* aWorkerPrivate
,
719 PromiseWorkerProxy
* aPromiseProxy
)
720 : WorkerRunnable(aWorkerPrivate
), mPromiseProxy(aPromiseProxy
) {
721 AssertIsOnMainThread();
724 virtual bool WorkerRun(JSContext
* aCx
,
725 WorkerPrivate
* aWorkerPrivate
) override
{
726 MOZ_ASSERT(aWorkerPrivate
);
727 aWorkerPrivate
->AssertIsOnWorkerThread();
729 RefPtr
<Promise
> promise
= mPromiseProxy
->WorkerPromise();
730 promise
->MaybeResolveWithUndefined();
732 // Release the reference on the worker thread.
733 mPromiseProxy
->CleanUp();
739 class WorkerScopeSkipWaitingRunnable final
: public Runnable
{
740 RefPtr
<PromiseWorkerProxy
> mPromiseProxy
;
744 WorkerScopeSkipWaitingRunnable(PromiseWorkerProxy
* aPromiseProxy
,
745 const nsCString
& aScope
)
746 : mozilla::Runnable("WorkerScopeSkipWaitingRunnable"),
747 mPromiseProxy(aPromiseProxy
),
749 MOZ_ASSERT(aPromiseProxy
);
754 AssertIsOnMainThread();
756 MutexAutoLock
lock(mPromiseProxy
->Lock());
757 if (mPromiseProxy
->CleanedUp()) {
761 WorkerPrivate
* workerPrivate
= mPromiseProxy
->GetWorkerPrivate();
762 MOZ_DIAGNOSTIC_ASSERT(workerPrivate
);
764 RefPtr
<ServiceWorkerManager
> swm
= ServiceWorkerManager::GetInstance();
766 swm
->SetSkipWaitingFlag(workerPrivate
->GetPrincipal(), mScope
,
767 workerPrivate
->ServiceWorkerID());
770 RefPtr
<SkipWaitingResultRunnable
> runnable
=
771 new SkipWaitingResultRunnable(workerPrivate
, mPromiseProxy
);
773 if (!runnable
->Dispatch()) {
774 NS_WARNING("Failed to dispatch SkipWaitingResultRunnable to the worker.");
782 already_AddRefed
<Promise
> ServiceWorkerGlobalScope::SkipWaiting(
784 mWorkerPrivate
->AssertIsOnWorkerThread();
785 MOZ_ASSERT(mWorkerPrivate
->IsServiceWorker());
787 RefPtr
<Promise
> promise
= Promise::Create(this, aRv
);
788 if (NS_WARN_IF(aRv
.Failed())) {
792 RefPtr
<PromiseWorkerProxy
> promiseProxy
=
793 PromiseWorkerProxy::Create(mWorkerPrivate
, promise
);
795 promise
->MaybeResolveWithUndefined();
796 return promise
.forget();
799 RefPtr
<WorkerScopeSkipWaitingRunnable
> runnable
=
800 new WorkerScopeSkipWaitingRunnable(promiseProxy
,
801 NS_ConvertUTF16toUTF8(mScope
));
803 MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate
->DispatchToMainThread(runnable
.forget()));
804 return promise
.forget();
807 WorkerDebuggerGlobalScope::WorkerDebuggerGlobalScope(
808 WorkerPrivate
* aWorkerPrivate
)
809 : mWorkerPrivate(aWorkerPrivate
),
810 mSerialEventTarget(aWorkerPrivate
->HybridEventTarget()) {
811 mWorkerPrivate
->AssertIsOnWorkerThread();
813 // We should always have an event target when the global is created.
814 MOZ_DIAGNOSTIC_ASSERT(mSerialEventTarget
);
816 // In workers, each DETH must have an owner. Because the global scope doesn't
817 // have an owner, let's set it as owner of itself.
818 BindToOwner(static_cast<nsIGlobalObject
*>(this));
821 WorkerDebuggerGlobalScope::~WorkerDebuggerGlobalScope() {
822 mWorkerPrivate
->AssertIsOnWorkerThread();
825 NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerDebuggerGlobalScope
)
827 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerDebuggerGlobalScope
,
828 DOMEventTargetHelper
)
829 tmp
->mWorkerPrivate
->AssertIsOnWorkerThread();
830 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole
)
831 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
833 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerDebuggerGlobalScope
,
834 DOMEventTargetHelper
)
835 tmp
->mWorkerPrivate
->AssertIsOnWorkerThread();
836 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole
)
837 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
839 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerDebuggerGlobalScope
,
840 DOMEventTargetHelper
)
841 tmp
->mWorkerPrivate
->AssertIsOnWorkerThread();
842 NS_IMPL_CYCLE_COLLECTION_TRACE_END
844 NS_IMPL_ADDREF_INHERITED(WorkerDebuggerGlobalScope
, DOMEventTargetHelper
)
845 NS_IMPL_RELEASE_INHERITED(WorkerDebuggerGlobalScope
, DOMEventTargetHelper
)
847 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerDebuggerGlobalScope
)
848 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject
)
849 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
851 bool WorkerDebuggerGlobalScope::WrapGlobalObject(
852 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aReflector
) {
853 mWorkerPrivate
->AssertIsOnWorkerThread();
855 JS::RealmOptions options
;
856 mWorkerPrivate
->CopyJSRealmOptions(options
);
858 return WorkerDebuggerGlobalScope_Binding::Wrap(
859 aCx
, this, this, options
, GetWorkerPrincipal(), true, aReflector
);
862 void WorkerDebuggerGlobalScope::GetGlobal(JSContext
* aCx
,
863 JS::MutableHandle
<JSObject
*> aGlobal
,
865 WorkerGlobalScope
* scope
= mWorkerPrivate
->GetOrCreateGlobalScope(aCx
);
867 aRv
.Throw(NS_ERROR_FAILURE
);
871 aGlobal
.set(scope
->GetWrapper());
874 void WorkerDebuggerGlobalScope::CreateSandbox(
875 JSContext
* aCx
, const nsAString
& aName
, JS::Handle
<JSObject
*> aPrototype
,
876 JS::MutableHandle
<JSObject
*> aResult
, ErrorResult
& aRv
) {
877 mWorkerPrivate
->AssertIsOnWorkerThread();
879 aResult
.set(nullptr);
881 JS::Rooted
<JS::Value
> protoVal(aCx
);
882 protoVal
.setObjectOrNull(aPrototype
);
883 JS::Rooted
<JSObject
*> sandbox(
885 SimpleGlobalObject::Create(
886 SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox
, protoVal
));
889 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
893 if (!JS_WrapObject(aCx
, &sandbox
)) {
894 aRv
.NoteJSContextException(aCx
);
898 aResult
.set(sandbox
);
901 void WorkerDebuggerGlobalScope::LoadSubScript(
902 JSContext
* aCx
, const nsAString
& aURL
,
903 const Optional
<JS::Handle
<JSObject
*>>& aSandbox
, ErrorResult
& aRv
) {
904 mWorkerPrivate
->AssertIsOnWorkerThread();
906 Maybe
<JSAutoRealm
> ar
;
907 if (aSandbox
.WasPassed()) {
908 // We only care about worker debugger sandbox objects here, so
909 // CheckedUnwrapStatic is fine.
910 JS::Rooted
<JSObject
*> sandbox(aCx
,
911 js::CheckedUnwrapStatic(aSandbox
.Value()));
912 if (!sandbox
|| !IsWorkerDebuggerSandbox(sandbox
)) {
913 aRv
.Throw(NS_ERROR_INVALID_ARG
);
917 ar
.emplace(aCx
, sandbox
);
920 nsTArray
<nsString
> urls
;
921 urls
.AppendElement(aURL
);
922 workerinternals::Load(mWorkerPrivate
, nullptr, urls
, DebuggerScript
, aRv
);
925 void WorkerDebuggerGlobalScope::EnterEventLoop() {
926 // We're on the worker thread here, and WorkerPrivate's refcounting is
927 // non-threadsafe: you can only do it on the parent thread. What that
928 // means in practice is that we're relying on it being kept alive while
929 // we run. Hopefully.
930 MOZ_KnownLive(mWorkerPrivate
)->EnterDebuggerEventLoop();
933 void WorkerDebuggerGlobalScope::LeaveEventLoop() {
934 mWorkerPrivate
->LeaveDebuggerEventLoop();
937 void WorkerDebuggerGlobalScope::PostMessage(const nsAString
& aMessage
) {
938 mWorkerPrivate
->PostMessageToDebugger(aMessage
);
941 void WorkerDebuggerGlobalScope::SetImmediate(Function
& aHandler
,
943 mWorkerPrivate
->SetDebuggerImmediate(aHandler
, aRv
);
946 void WorkerDebuggerGlobalScope::ReportError(JSContext
* aCx
,
947 const nsAString
& aMessage
) {
948 JS::AutoFilename chars
;
950 JS::DescribeScriptedCaller(aCx
, &chars
, &lineno
);
951 nsString
filename(NS_ConvertUTF8toUTF16(chars
.get()));
952 mWorkerPrivate
->ReportErrorToDebugger(filename
, lineno
, aMessage
);
955 void WorkerDebuggerGlobalScope::RetrieveConsoleEvents(
956 JSContext
* aCx
, nsTArray
<JS::Value
>& aEvents
, ErrorResult
& aRv
) {
957 WorkerGlobalScope
* scope
= mWorkerPrivate
->GetOrCreateGlobalScope(aCx
);
959 aRv
.Throw(NS_ERROR_FAILURE
);
963 RefPtr
<Console
> console
= scope
->GetConsole(aRv
);
964 if (NS_WARN_IF(aRv
.Failed())) {
968 console
->RetrieveConsoleEvents(aCx
, aEvents
, aRv
);
971 void WorkerDebuggerGlobalScope::SetConsoleEventHandler(JSContext
* aCx
,
972 AnyCallback
* aHandler
,
974 WorkerGlobalScope
* scope
= mWorkerPrivate
->GetOrCreateGlobalScope(aCx
);
976 aRv
.Throw(NS_ERROR_FAILURE
);
980 RefPtr
<Console
> console
= scope
->GetConsole(aRv
);
981 if (NS_WARN_IF(aRv
.Failed())) {
985 console
->SetConsoleEventHandler(aHandler
);
988 already_AddRefed
<Console
> WorkerDebuggerGlobalScope::GetConsole(
990 mWorkerPrivate
->AssertIsOnWorkerThread();
992 // Debugger console has its own console object.
994 mConsole
= Console::Create(mWorkerPrivate
->GetJSContext(), nullptr, aRv
);
995 if (NS_WARN_IF(aRv
.Failed())) {
1000 RefPtr
<Console
> console
= mConsole
;
1001 return console
.forget();
1004 void WorkerDebuggerGlobalScope::Dump(JSContext
* aCx
,
1005 const Optional
<nsAString
>& aString
) const {
1006 WorkerGlobalScope
* scope
= mWorkerPrivate
->GetOrCreateGlobalScope(aCx
);
1008 scope
->Dump(aString
);
1012 void WorkerDebuggerGlobalScope::Atob(const nsAString
& aAtob
, nsAString
& aOutput
,
1013 ErrorResult
& aRv
) const {
1014 mWorkerPrivate
->AssertIsOnWorkerThread();
1015 aRv
= nsContentUtils::Atob(aAtob
, aOutput
);
1018 void WorkerDebuggerGlobalScope::Btoa(const nsAString
& aBtoa
, nsAString
& aOutput
,
1019 ErrorResult
& aRv
) const {
1020 mWorkerPrivate
->AssertIsOnWorkerThread();
1021 aRv
= nsContentUtils::Btoa(aBtoa
, aOutput
);
1024 nsresult
WorkerDebuggerGlobalScope::Dispatch(
1025 TaskCategory aCategory
, already_AddRefed
<nsIRunnable
>&& aRunnable
) {
1026 return EventTargetFor(aCategory
)->Dispatch(std::move(aRunnable
),
1027 NS_DISPATCH_NORMAL
);
1030 nsISerialEventTarget
* WorkerDebuggerGlobalScope::EventTargetFor(
1031 TaskCategory aCategory
) const {
1032 return mSerialEventTarget
;
1035 AbstractThread
* WorkerDebuggerGlobalScope::AbstractMainThreadFor(
1036 TaskCategory aCategory
) {
1037 MOZ_CRASH("AbstractMainThreadFor not supported for workers.");
1040 bool IsWorkerGlobal(JSObject
* object
) {
1041 return IS_INSTANCE_OF(WorkerGlobalScope
, object
);
1044 bool IsWorkerDebuggerGlobal(JSObject
* object
) {
1045 return IS_INSTANCE_OF(WorkerDebuggerGlobalScope
, object
);
1048 bool IsWorkerDebuggerSandbox(JSObject
* object
) {
1049 return SimpleGlobalObject::SimpleGlobalType(object
) ==
1050 SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox
;
1054 } // namespace mozilla