Bug 1550519 - Show a translucent parent highlight when a subgrid is highlighted....
[gecko.git] / dom / workers / WorkerScope.cpp
blob34a9240cd4214bad796eaf83730ec78ec5702a4a
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"
9 #include "jsapi.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"
43 #ifdef ANDROID
44 # include <android/log.h>
45 #endif
47 #include "Crypto.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"
56 #ifdef XP_WIN
57 # undef PostMessage
58 #endif
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);
70 namespace mozilla {
71 namespace dom {
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,
97 DOMEventTargetHelper)
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();
144 StartDying();
147 already_AddRefed<Console> WorkerGlobalScope::GetConsole(ErrorResult& aRv) {
148 mWorkerPrivate->AssertIsOnWorkerThread();
150 if (!mConsole) {
151 mConsole = Console::Create(mWorkerPrivate->GetJSContext(), nullptr, aRv);
152 if (NS_WARN_IF(aRv.Failed())) {
153 return nullptr;
157 RefPtr<Console> console = mConsole;
158 return console.forget();
161 Crypto* WorkerGlobalScope::GetCrypto(ErrorResult& aError) {
162 mWorkerPrivate->AssertIsOnWorkerThread();
164 if (!mCrypto) {
165 mCrypto = new Crypto(this);
168 return mCrypto;
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;
179 return ref.forget();
182 bool WorkerGlobalScope::IsSecureContext() const {
183 bool globalSecure = JS::GetIsSecureContext(
184 js::GetNonCCWObjectRealm(GetWrapperPreserveColor()));
185 MOZ_ASSERT(globalSecure == mWorkerPrivate->IsSecureContext());
186 return globalSecure;
189 already_AddRefed<WorkerLocation> WorkerGlobalScope::Location() {
190 mWorkerPrivate->AssertIsOnWorkerThread();
192 if (!mLocation) {
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();
206 if (!mNavigator) {
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()
216 const {
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();
234 if (elm) {
235 elm->SetEventHandler(aHandler);
239 void WorkerGlobalScope::ImportScripts(JSContext* aCx,
240 const Sequence<nsString>& aScriptURLs,
241 ErrorResult& aRv) {
242 mWorkerPrivate->AssertIsOnWorkerThread();
244 UniquePtr<SerializedStackHolder> stack;
245 if (mWorkerPrivate->IsWatchedByDevtools()) {
246 stack = GetCurrentStackForNetMonitor(aCx);
249 workerinternals::Load(mWorkerPrivate, std::move(stack), aScriptURLs,
250 WorkerScript, aRv);
253 int32_t WorkerGlobalScope::SetTimeout(JSContext* aCx, Function& aHandler,
254 const int32_t aTimeout,
255 const Sequence<JS::Value>& aArguments,
256 ErrorResult& aRv) {
257 mWorkerPrivate->AssertIsOnWorkerThread();
259 nsCOMPtr<nsIScriptTimeoutHandler> handler =
260 NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aArguments, aRv);
261 if (!handler) {
262 return 0;
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 */,
271 ErrorResult& aRv) {
272 mWorkerPrivate->AssertIsOnWorkerThread();
274 nsCOMPtr<nsIScriptTimeoutHandler> handler =
275 NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aRv);
276 if (!handler) {
277 return 0;
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,
291 ErrorResult& aRv) {
292 mWorkerPrivate->AssertIsOnWorkerThread();
294 nsCOMPtr<nsIScriptTimeoutHandler> handler =
295 NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aArguments, aRv);
296 if (NS_WARN_IF(aRv.Failed())) {
297 return 0;
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 */,
307 ErrorResult& aRv) {
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())) {
315 return 0;
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()) {
347 return;
350 #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
351 if (!DOMPrefs::DumpEnabled()) {
352 return;
354 #endif
356 NS_ConvertUTF16toUTF8 str(aString.Value());
358 MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug,
359 ("[Worker.Dump] %s", str.get()));
360 #ifdef ANDROID
361 __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", str.get());
362 #endif
363 fputs(str.get(), stdout);
364 fflush(stdout);
367 Performance* WorkerGlobalScope::GetPerformance() {
368 mWorkerPrivate->AssertIsOnWorkerThread();
370 if (!mPerformance) {
371 mPerformance = Performance::CreateForWorker(mWorkerPrivate);
374 return mPerformance;
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);
384 if (!obj) {
385 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
386 return;
389 aFunctions.set(obj);
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;
404 if (!indexedDB) {
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;
410 return nullptr;
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;
417 return nullptr;
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))) {
427 aErrorResult = rv;
428 return nullptr;
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),
452 NS_DISPATCH_NORMAL);
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());
472 return state;
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)) {
487 return;
490 ref = swr.forget();
491 *aDoneOut = true;
493 return ref.forget();
496 RefPtr<ServiceWorkerRegistration>
497 WorkerGlobalScope::GetOrCreateServiceWorkerRegistration(
498 const ServiceWorkerRegistrationDescriptor& aDescriptor) {
499 mWorkerPrivate->AssertIsOnWorkerThread();
500 RefPtr<ServiceWorkerRegistration> ref =
501 GetServiceWorkerRegistration(aDescriptor);
502 if (!ref) {
503 ref = ServiceWorkerRegistration::CreateForWorker(mWorkerPrivate, this,
504 aDescriptor);
506 return ref.forget();
509 void WorkerGlobalScope::FirstPartyStorageAccessGranted() {
510 // Reset the IndexedDB factory.
511 mIndexedDB = nullptr;
513 // Reset DOM Cache
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()
542 .set(extraWarnings);
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,
560 ErrorResult& aRv) {
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.
609 mRegistration(
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() {
627 if (!mClients) {
628 mClients = new Clients(this);
631 RefPtr<Clients> ref = mClients;
632 return ref.forget();
635 ServiceWorkerRegistration* ServiceWorkerGlobalScope::Registration() {
636 return mRegistration;
639 EventHandlerNonNull* ServiceWorkerGlobalScope::GetOnfetch() {
640 MOZ_ASSERT(mWorkerPrivate);
641 mWorkerPrivate->AssertIsOnWorkerThread();
643 return GetEventHandler(nsGkAtoms::onfetch);
646 namespace {
648 class ReportFetchListenerWarningRunnable final : public Runnable {
649 const nsCString mScope;
650 nsCString mSourceSpec;
651 uint32_t mLine;
652 uint32_t mColumn;
654 public:
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();
661 MOZ_ASSERT(cx);
663 nsJSUtils::GetCallingLocation(cx, mSourceSpec, &mLine, &mColumn);
666 NS_IMETHOD
667 Run() override {
668 AssertIsOnMainThread();
670 ServiceWorkerManager::LocalizeAndReportToAllClients(
671 mScope, "ServiceWorkerNoFetchHandler", nsTArray<nsString>{},
672 nsIScriptError::warningFlag, NS_ConvertUTF8toUTF16(mSourceSpec),
673 EmptyString(), mLine, mColumn);
675 return NS_OK;
679 } // anonymous namespace
681 void ServiceWorkerGlobalScope::SetOnfetch(
682 mozilla::dom::EventHandlerNonNull* aCallback) {
683 MOZ_ASSERT(mWorkerPrivate);
684 mWorkerPrivate->AssertIsOnWorkerThread();
686 if (aCallback) {
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) {
701 return;
704 if (mWorkerPrivate->WorkerScriptExecutedSuccessfully()) {
705 RefPtr<Runnable> r = new ReportFetchListenerWarningRunnable(mScope);
706 mWorkerPrivate->DispatchToMainThreadForMessaging(r.forget());
709 mWorkerPrivate->SetFetchHandlerWasAdded();
712 namespace {
714 class SkipWaitingResultRunnable final : public WorkerRunnable {
715 RefPtr<PromiseWorkerProxy> mPromiseProxy;
717 public:
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();
735 return true;
739 class WorkerScopeSkipWaitingRunnable final : public Runnable {
740 RefPtr<PromiseWorkerProxy> mPromiseProxy;
741 nsCString mScope;
743 public:
744 WorkerScopeSkipWaitingRunnable(PromiseWorkerProxy* aPromiseProxy,
745 const nsCString& aScope)
746 : mozilla::Runnable("WorkerScopeSkipWaitingRunnable"),
747 mPromiseProxy(aPromiseProxy),
748 mScope(aScope) {
749 MOZ_ASSERT(aPromiseProxy);
752 NS_IMETHOD
753 Run() override {
754 AssertIsOnMainThread();
756 MutexAutoLock lock(mPromiseProxy->Lock());
757 if (mPromiseProxy->CleanedUp()) {
758 return NS_OK;
761 WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
762 MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
764 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
765 if (swm) {
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.");
776 return NS_OK;
780 } // namespace
782 already_AddRefed<Promise> ServiceWorkerGlobalScope::SkipWaiting(
783 ErrorResult& aRv) {
784 mWorkerPrivate->AssertIsOnWorkerThread();
785 MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
787 RefPtr<Promise> promise = Promise::Create(this, aRv);
788 if (NS_WARN_IF(aRv.Failed())) {
789 return nullptr;
792 RefPtr<PromiseWorkerProxy> promiseProxy =
793 PromiseWorkerProxy::Create(mWorkerPrivate, promise);
794 if (!promiseProxy) {
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,
864 ErrorResult& aRv) {
865 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
866 if (!scope) {
867 aRv.Throw(NS_ERROR_FAILURE);
868 return;
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(
884 aCx,
885 SimpleGlobalObject::Create(
886 SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox, protoVal));
888 if (!sandbox) {
889 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
890 return;
893 if (!JS_WrapObject(aCx, &sandbox)) {
894 aRv.NoteJSContextException(aCx);
895 return;
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);
914 return;
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,
942 ErrorResult& aRv) {
943 mWorkerPrivate->SetDebuggerImmediate(aHandler, aRv);
946 void WorkerDebuggerGlobalScope::ReportError(JSContext* aCx,
947 const nsAString& aMessage) {
948 JS::AutoFilename chars;
949 uint32_t lineno = 0;
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);
958 if (!scope) {
959 aRv.Throw(NS_ERROR_FAILURE);
960 return;
963 RefPtr<Console> console = scope->GetConsole(aRv);
964 if (NS_WARN_IF(aRv.Failed())) {
965 return;
968 console->RetrieveConsoleEvents(aCx, aEvents, aRv);
971 void WorkerDebuggerGlobalScope::SetConsoleEventHandler(JSContext* aCx,
972 AnyCallback* aHandler,
973 ErrorResult& aRv) {
974 WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
975 if (!scope) {
976 aRv.Throw(NS_ERROR_FAILURE);
977 return;
980 RefPtr<Console> console = scope->GetConsole(aRv);
981 if (NS_WARN_IF(aRv.Failed())) {
982 return;
985 console->SetConsoleEventHandler(aHandler);
988 already_AddRefed<Console> WorkerDebuggerGlobalScope::GetConsole(
989 ErrorResult& aRv) {
990 mWorkerPrivate->AssertIsOnWorkerThread();
992 // Debugger console has its own console object.
993 if (!mConsole) {
994 mConsole = Console::Create(mWorkerPrivate->GetJSContext(), nullptr, aRv);
995 if (NS_WARN_IF(aRv.Failed())) {
996 return nullptr;
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);
1007 if (scope) {
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;
1053 } // namespace dom
1054 } // namespace mozilla