/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_workerscope_h__ #define mozilla_dom_workerscope_h__ #include "js/TypeDecls.h" #include "js/loader/ModuleLoaderBase.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/Maybe.h" #include "mozilla/NotNull.h" #include "mozilla/RefPtr.h" #include "mozilla/UniquePtr.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/AnimationFrameProvider.h" #include "mozilla/dom/ImageBitmapBinding.h" #include "mozilla/dom/ImageBitmapSource.h" #include "mozilla/dom/PerformanceWorker.h" #include "mozilla/dom/SafeRefPtr.h" #include "mozilla/dom/TrustedTypePolicyFactory.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/TimeoutManager.h" #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" #include "nsIGlobalObject.h" #include "nsISupports.h" #include "nsWeakReference.h" #ifdef XP_WIN # undef PostMessage #endif class nsAtom; class nsISerialEventTarget; namespace mozilla { class ErrorResult; struct VsyncEvent; namespace extensions { class ExtensionBrowser; } // namespace extensions namespace dom { class AnyCallback; enum class CallerType : uint32_t; class ClientInfo; class ClientSource; class Clients; class Console; class CookieStore; class Crypto; class DOMString; class DebuggerNotificationManager; enum class EventCallbackDebuggerNotificationType : uint8_t; class EventHandlerNonNull; class FontFaceSet; class Function; class FunctionOrTrustedScriptOrString; class IDBFactory; class OnErrorEventHandlerNonNull; template class Optional; class OwningTrustedScriptURLOrString; class Performance; class Promise; class RequestOrUTF8String; template class Sequence; class ServiceWorkerDescriptor; class ServiceWorkerRegistration; class ServiceWorkerRegistrationDescriptor; struct StructuredSerializeOptions; class WorkerDocumentListener; class WorkerLocation; class WorkerNavigator; class WorkerPrivate; class VsyncWorkerChild; class WebTaskScheduler; class WebTaskSchedulerWorker; class WebTaskSchedulingState; struct RequestInit; namespace cache { class CacheStorage; } // namespace cache class WorkerGlobalScopeBase : public DOMEventTargetHelper, public nsSupportsWeakReference, public nsIGlobalObject { friend class WorkerPrivate; public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerGlobalScopeBase, DOMEventTargetHelper) WorkerGlobalScopeBase(WorkerPrivate* aWorkerPrivate, UniquePtr aClientSource); mozilla::dom::TimeoutManager* GetTimeoutManager() override final { return mTimeoutManager.get(); } virtual bool WrapGlobalObject(JSContext* aCx, JS::MutableHandle aReflector) = 0; // EventTarget implementation JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) final { MOZ_CRASH("WrapObject not supported; use WrapGlobalObject."); } // nsIGlobalObject implementation JSObject* GetGlobalJSObject() final; JSObject* GetGlobalJSObjectPreserveColor() const final; bool IsSharedMemoryAllowed() const final; bool ShouldResistFingerprinting(RFPTarget aTarget) const final; OriginTrials Trials() const final; StorageAccess GetStorageAccess() final; nsICookieJarSettings* GetCookieJarSettings() final; nsIURI* GetBaseURI() const final; Maybe GetClientInfo() const final; Maybe GetClientState() const final; Maybe GetController() const final; mozilla::Result GetStorageKey() final; virtual void Control(const ServiceWorkerDescriptor& aServiceWorker); // DispatcherTrait implementation nsresult Dispatch(already_AddRefed&& aRunnable) const final; nsISerialEventTarget* SerialEventTarget() const final; MOZ_CAN_RUN_SCRIPT void ReportError(JSContext* aCx, JS::Handle aError, CallerType aCallerType, ErrorResult& aRv); // atob, btoa, and dump are declared (separately) by both WorkerGlobalScope // and WorkerDebuggerGlobalScope WebIDL interfaces void Atob(const nsAString& aAtob, nsAString& aOut, ErrorResult& aRv) const; void Btoa(const nsAString& aBtoa, nsAString& aOut, ErrorResult& aRv) const; already_AddRefed GetConsole(ErrorResult& aRv); Console* GetConsoleIfExists() const { return mConsole; } void InitModuleLoader(JS::loader::ModuleLoaderBase* aModuleLoader) { if (!mModuleLoader) { mModuleLoader = aModuleLoader; } } // The nullptr here is not used, but is required to make the override method // have the same signature as other GetModuleLoader methods on globals. JS::loader::ModuleLoaderBase* GetModuleLoader( JSContext* aCx = nullptr) override { return mModuleLoader; }; uint64_t WindowID() const; // Usually global scope dies earlier than the WorkerPrivate, but if we see // it leak at least we can tell it to not carry away a dead pointer. void NoteWorkerTerminated() { mWorkerPrivate = nullptr; } ClientSource& MutableClientSourceRef() const { return *mClientSource; } bool IsBackgroundInternal() const override { MOZ_ASSERT(mWorkerPrivate); return mWorkerPrivate->IsRunningInBackground(); } MOZ_CAN_RUN_SCRIPT bool RunTimeoutHandler( mozilla::dom::Timeout* aTimeout) override; bool IsFrozen() const override { return mWorkerPrivate->IsFrozenForWorkerThread(); } // workers don't support both frozen and suspended, // either both are true, or both are false. bool IsSuspended() const override { return mWorkerPrivate->IsFrozenForWorkerThread(); } void UpdateWebSocketCount(int32_t aDelta) override { if (aDelta == 0) { return; } MOZ_DIAGNOSTIC_ASSERT( aDelta > 0 || ((aDelta + mNumOfOpenWebSockets) < mNumOfOpenWebSockets)); mNumOfOpenWebSockets += aDelta; } // Increase/Decrease the number of active IndexedDB databases for the // decision making of timeout-throttling. void UpdateActiveIndexedDBDatabaseCount(int32_t aDelta) override { AssertIsOnWorkerThread(); mNumOfIndexedDBDatabases += aDelta; } bool HasOpenWebSockets() const override { return mNumOfOpenWebSockets; } bool HasActiveIndexedDBDatabases() const override { AssertIsOnWorkerThread(); return mNumOfIndexedDBDatabases; } bool IsPlayingAudio() override { AssertIsOnWorkerThread(); return mWorkerPrivate && mWorkerPrivate->IsPlayingAudio(); } void TriggerUpdateCCFlag() override { mWorkerPrivate->UpdateCCFlag(WorkerPrivate::CCFlag::EligibleForTimeout); } static WorkerGlobalScopeBase* Cast(nsIGlobalObject* obj) { return static_cast(obj); } protected: ~WorkerGlobalScopeBase(); CheckedUnsafePtr mWorkerPrivate; void AssertIsOnWorkerThread() const { MOZ_ASSERT(mWorkerThreadUsedOnlyForAssert == PR_GetCurrentThread()); } private: RefPtr mConsole; RefPtr mModuleLoader; const UniquePtr mClientSource; nsCOMPtr mSerialEventTarget; #ifdef DEBUG PRThread* mWorkerThreadUsedOnlyForAssert; #endif mozilla::UniquePtr mTimeoutManager; uint32_t mNumOfOpenWebSockets{}; uint32_t mNumOfIndexedDBDatabases{}; }; namespace workerinternals { class NamedWorkerGlobalScopeMixin { public: explicit NamedWorkerGlobalScopeMixin(const nsAString& aName) : mName(aName) {} void GetName(DOMString& aName) const; protected: ~NamedWorkerGlobalScopeMixin() = default; private: const nsString mName; }; } // namespace workerinternals class WorkerGlobalScope : public WorkerGlobalScopeBase { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WorkerGlobalScope, WorkerGlobalScopeBase) using WorkerGlobalScopeBase::WorkerGlobalScopeBase; void NoteTerminating(); void NoteShuttingDown(); // nsIGlobalObject implementation already_AddRefed GetServiceWorkerContainer() final; RefPtr GetOrCreateServiceWorker( const ServiceWorkerDescriptor& aDescriptor) final; RefPtr GetServiceWorkerRegistration( const ServiceWorkerRegistrationDescriptor& aDescriptor) const final; RefPtr GetOrCreateServiceWorkerRegistration( const ServiceWorkerRegistrationDescriptor& aDescriptor) final; DebuggerNotificationManager* GetOrCreateDebuggerNotificationManager() final; DebuggerNotificationManager* GetExistingDebuggerNotificationManager() final; Maybe GetDebuggerNotificationType() const final; mozilla::dom::StorageManager* GetStorageManager() final; void SetIsNotEligibleForMessaging() { mIsEligibleForMessaging = false; } bool IsEligibleForMessaging() final; void ReportToConsole(uint32_t aErrorFlags, const nsCString& aCategory, nsContentUtils::PropertiesFile aFile, const nsCString& aMessageName, const nsTArray& aParams, const mozilla::SourceLocation& aLocation) final; // WorkerGlobalScope WebIDL implementation WorkerGlobalScope* Self() { return this; } already_AddRefed Location(); already_AddRefed Navigator(); already_AddRefed GetExistingNavigator() const; FontFaceSet* GetFonts(ErrorResult&); FontFaceSet* GetFonts() final { return GetFonts(IgnoreErrors()); } MOZ_CAN_RUN_SCRIPT void ImportScripts( JSContext* aCx, const Sequence& aScriptURLs, ErrorResult& aRv); OnErrorEventHandlerNonNull* GetOnerror(); void SetOnerror(OnErrorEventHandlerNonNull* aHandler); IMPL_EVENT_HANDLER(languagechange) IMPL_EVENT_HANDLER(offline) IMPL_EVENT_HANDLER(online) IMPL_EVENT_HANDLER(rejectionhandled) IMPL_EVENT_HANDLER(unhandledrejection) void Dump(const Optional& aString) const; Performance* GetPerformance(); Performance* GetPerformanceIfExists() const { return mPerformance; } static bool IsInAutomation(JSContext* aCx, JSObject*); void GetJSTestingFunctions(JSContext* aCx, JS::MutableHandle aFunctions, ErrorResult& aRv); // GlobalCrypto WebIDL implementation Crypto* GetCrypto(ErrorResult& aError); // WindowOrWorkerGlobalScope WebIDL implementation void GetOrigin(nsAString& aOrigin) const; bool CrossOriginIsolated() const final; MOZ_CAN_RUN_SCRIPT int32_t SetTimeout(JSContext* aCx, const FunctionOrTrustedScriptOrString& aHandler, int32_t aTimeout, const Sequence& aArguments, nsIPrincipal* aSubjectPrincipal, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT void ClearTimeout(int32_t aHandle); MOZ_CAN_RUN_SCRIPT int32_t SetInterval(JSContext* aCx, const FunctionOrTrustedScriptOrString& aHandler, int32_t aTimeout, const Sequence& aArguments, nsIPrincipal* aSubjectPrincipal, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT void ClearInterval(int32_t aHandle); already_AddRefed CreateImageBitmap( const ImageBitmapSource& aImage, const ImageBitmapOptions& aOptions, ErrorResult& aRv); already_AddRefed CreateImageBitmap( const ImageBitmapSource& aImage, int32_t aSx, int32_t aSy, int32_t aSw, int32_t aSh, const ImageBitmapOptions& aOptions, ErrorResult& aRv); void StructuredClone(JSContext* aCx, JS::Handle aValue, const StructuredSerializeOptions& aOptions, JS::MutableHandle aRetval, ErrorResult& aError); already_AddRefed Fetch(const RequestOrUTF8String& aInput, const RequestInit& aInit, CallerType aCallerType, ErrorResult& aRv); bool IsSecureContext() const; already_AddRefed GetIndexedDB(JSContext* aCx, ErrorResult& aErrorResult); already_AddRefed GetCaches(ErrorResult& aRv); WebTaskScheduler* Scheduler(); WebTaskScheduler* GetExistingScheduler() const; void SetWebTaskSchedulingState(WebTaskSchedulingState* aState) override; bool HasScheduledNormalOrHighPriorityWebTasks() const override; WebTaskSchedulingState* GetWebTaskSchedulingState() const override { return mWebTaskSchedulingState; } bool WindowInteractionAllowed() const; void AllowWindowInteraction(); void ConsumeWindowInteraction(); void StorageAccessPermissionGranted(); virtual void OnDocumentVisible(bool aVisible) {} MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void OnVsync(const VsyncEvent& aVsync) {} TrustedTypePolicyFactory* TrustedTypes(); protected: ~WorkerGlobalScope(); private: MOZ_CAN_RUN_SCRIPT int32_t SetTimeoutOrInterval( JSContext* aCx, const FunctionOrTrustedScriptOrString& aHandler, int32_t aTimeout, const Sequence& aArguments, bool aIsInterval, nsIPrincipal* aSubjectPrincipal, ErrorResult& aRv); RefPtr mCrypto; RefPtr mLocation; RefPtr mNavigator; RefPtr mFontFaceSet; RefPtr mPerformance; RefPtr mIndexedDB; RefPtr mCacheStorage; RefPtr mDebuggerNotificationManager; RefPtr mWebTaskScheduler; RefPtr mWebTaskSchedulingState; RefPtr mTrustedTypePolicyFactory; uint32_t mWindowInteractionsAllowed = 0; bool mIsEligibleForMessaging{true}; }; class DedicatedWorkerGlobalScope final : public WorkerGlobalScope, public workerinternals::NamedWorkerGlobalScopeMixin { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED( DedicatedWorkerGlobalScope, WorkerGlobalScope) DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, UniquePtr aClientSource, const nsString& aName); bool WrapGlobalObject(JSContext* aCx, JS::MutableHandle aReflector) override; void PostMessage(JSContext* aCx, JS::Handle aMessage, const Sequence& aTransferable, ErrorResult& aRv); void PostMessage(JSContext* aCx, JS::Handle aMessage, const StructuredSerializeOptions& aOptions, ErrorResult& aRv); void Close(); MOZ_CAN_RUN_SCRIPT uint32_t RequestAnimationFrame(FrameRequestCallback& aCallback, ErrorResult& aError); MOZ_CAN_RUN_SCRIPT void CancelAnimationFrame(uint32_t aHandle, ErrorResult& aError); void OnDocumentVisible(bool aVisible) override; MOZ_CAN_RUN_SCRIPT_BOUNDARY void OnVsync(const VsyncEvent& aVsync) override; IMPL_EVENT_HANDLER(message) IMPL_EVENT_HANDLER(messageerror) IMPL_EVENT_HANDLER(rtctransform) private: ~DedicatedWorkerGlobalScope() = default; FrameRequestManager mFrameRequestManager; RefPtr mVsyncChild; RefPtr mDocListener; bool mDocumentVisible = false; }; class SharedWorkerGlobalScope final : public WorkerGlobalScope, public workerinternals::NamedWorkerGlobalScopeMixin { public: SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, UniquePtr aClientSource, const nsString& aName); bool WrapGlobalObject(JSContext* aCx, JS::MutableHandle aReflector) override; void Close(); IMPL_EVENT_HANDLER(connect) private: ~SharedWorkerGlobalScope() = default; }; class ServiceWorkerGlobalScope final : public WorkerGlobalScope { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope) ServiceWorkerGlobalScope( WorkerPrivate* aWorkerPrivate, UniquePtr aClientSource, const ServiceWorkerRegistrationDescriptor& aRegistrationDescriptor); bool WrapGlobalObject(JSContext* aCx, JS::MutableHandle aReflector) override; already_AddRefed GetClients(); ServiceWorkerRegistration* Registration(); already_AddRefed SkipWaiting(ErrorResult& aRv); SafeRefPtr AcquireExtensionBrowser(); IMPL_EVENT_HANDLER(install) IMPL_EVENT_HANDLER(activate) EventHandlerNonNull* GetOnfetch(); void SetOnfetch(EventHandlerNonNull* aCallback); void EventListenerAdded(nsAtom* aType) override; already_AddRefed CookieStore(); IMPL_EVENT_HANDLER(message) IMPL_EVENT_HANDLER(messageerror) IMPL_EVENT_HANDLER(notificationclick) IMPL_EVENT_HANDLER(notificationclose) IMPL_EVENT_HANDLER(push) IMPL_EVENT_HANDLER(pushsubscriptionchange) IMPL_EVENT_HANDLER(cookiechange) private: ~ServiceWorkerGlobalScope(); void NoteFetchHandlerWasAdded() const; RefPtr mClients; const nsString mScope; RefPtr mRegistration; SafeRefPtr mExtensionBrowser; RefPtr mCookieStore; }; class WorkerDebuggerGlobalScope final : public WorkerGlobalScopeBase { public: using WorkerGlobalScopeBase::WorkerGlobalScopeBase; bool WrapGlobalObject(JSContext* aCx, JS::MutableHandle aReflector) override; void Control(const ServiceWorkerDescriptor& aServiceWorker) override { MOZ_CRASH("Can't control debugger workers."); } void GetGlobal(JSContext* aCx, JS::MutableHandle aGlobal, ErrorResult& aRv); void CreateSandbox(JSContext* aCx, const nsAString& aName, JS::Handle aPrototype, JS::MutableHandle aResult, ErrorResult& aRv); void LoadSubScript(JSContext* aCx, const nsAString& aUrl, const Optional>& aSandbox, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT void EnterEventLoop(); void LeaveEventLoop(); void PostMessage(const nsAString& aMessage); void SetImmediate(Function& aHandler, ErrorResult& aRv); void ReportError(JSContext* aCx, const nsAString& aMessage); void RetrieveConsoleEvents(JSContext* aCx, nsTArray& aEvents, ErrorResult& aRv); void ClearConsoleEvents(JSContext* aCx, ErrorResult& aRv); void SetConsoleEventHandler(JSContext* aCx, AnyCallback* aHandler, ErrorResult& aRv); void Dump(JSContext* aCx, const Optional& aString) const; IMPL_EVENT_HANDLER(message) IMPL_EVENT_HANDLER(messageerror) private: ~WorkerDebuggerGlobalScope() = default; }; } // namespace dom } // namespace mozilla inline nsISupports* ToSupports(mozilla::dom::WorkerGlobalScope* aScope) { return static_cast(aScope); } #endif /* mozilla_dom_workerscope_h__ */