/* -*- 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_extensions_ExtensionBrowser_h #define mozilla_extensions_ExtensionBrowser_h #include "nsCOMPtr.h" #include "nsISupports.h" #include "nsTHashMap.h" #include "nsWrapperCache.h" #include "mozilla/WeakPtr.h" #include "xpcpublic.h" class nsIGlobalObject; class nsIURI; namespace mozilla { class ErrorResult; namespace extensions { class ExtensionAlarms; class ExtensionBrowserSettings; class ExtensionDns; class ExtensionMockAPI; class ExtensionPort; class ExtensionProxy; class ExtensionRuntime; class ExtensionScripting; class ExtensionTest; bool ExtensionAPIAllowed(JSContext* aCx, JSObject* aGlobal); void CreateAndDispatchInitWorkerContextRunnable(); already_AddRefed CreateWorkerLoadedRunnable( const uint64_t aServiceWorkerDescriptorId, const nsCOMPtr& aWorkerBaseURI); already_AddRefed CreateWorkerDestroyedRunnable( const uint64_t aServiceWorkerDescriptorId, const nsCOMPtr& aWorkerBaseURI); // An HashMap used to keep track of listeners registered synchronously while // the worker script is executing, used internally by nsIServiceWorkerManager // wakeforExtensionAPIEvent method to resolve to true if the worker script // spawned did have a listener subscribed for the related API event name. class ExtensionEventWakeupMap final : public nsTHashMap { static void ToMapKey(const nsAString& aAPINamespace, const nsAString& aAPIName, nsAString& aResultMapKey); public: nsresult IncrementListeners(const nsAString& aAPINamespace, const nsAString& aAPIName); nsresult DecrementListeners(const nsAString& aAPINamespace, const nsAString& aAPIName); bool HasListener(const nsAString& aAPINamespace, const nsAString& aAPIName); }; class ExtensionBrowser final : public nsISupports, public nsWrapperCache { public: explicit ExtensionBrowser(nsIGlobalObject* aGlobal); // Helpers used for the expected behavior of the browser.runtime.lastError // and browser.extension.lastError. void SetLastError(JS::Handle aLastError); void GetLastError(JS::MutableHandle aRetVal); // ClearLastError is used by ChromeCompatCallbackHandler::RejectedCallback // to clear the lastError property. When this method returns true the // caller will know that the error value wasn't checked by the callback and // should be reported to the console bool ClearLastError(); // Helpers used to keep track of the event listeners added during the // initial sync worker script execution. nsresult TrackWakeupEventListener(JSContext* aCx, const nsString& aAPINamespace, const nsString& aAPIName); nsresult UntrackWakeupEventListener(JSContext* aCx, const nsString& aAPINamespace, const nsString& aAPIName); bool HasWakeupEventListener(const nsString& aAPINamespace, const nsString& aAPIName); // Helpers used for the ExtensionPort. // Get an ExtensionPort instance given its port descriptor (returns an // existing port if an instance is still tracked in the ports lookup table, // otherwise it creates a new one). already_AddRefed GetPort( JS::Handle aDescriptorValue, ErrorResult& aRv); // Remove the entry for an ExtensionPort tracked in the ports lookup map // given its portId (called from the ExtensionPort destructor when the // instance is being released). void ForgetReleasedPort(const nsAString& aPortId); // nsWrapperCache interface methods JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; // DOM bindings methods nsIGlobalObject* GetParentObject() const; ExtensionAlarms* GetExtensionAlarms(); ExtensionBrowserSettings* GetExtensionBrowserSettings(); ExtensionDns* GetExtensionDns(); ExtensionMockAPI* GetExtensionMockAPI(); ExtensionProxy* GetExtensionProxy(); ExtensionRuntime* GetExtensionRuntime(); ExtensionScripting* GetExtensionScripting(); ExtensionTest* GetExtensionTest(); NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionBrowser) private: ~ExtensionBrowser() = default; nsCOMPtr mGlobal; JS::Heap mLastError; bool mCheckedLastError; nsTHashMap> mPortsLookup; // `[APINamespace].[APIName]` => int64 (listeners count) ExtensionEventWakeupMap mExpectedEventWakeupMap; // NOTE: Make sure to don't forget to add for new API namespace instances // added to the ones listed below the `NS_IMPL_CYCLE_COLLECTION_UNLINK` and // `NS_IMPL_CYCLE_COLLECTION_TRAVERSE` macro calls in ExtensionBrowser.cpp, // forgetting it would not result in a build error but it would leak the API // namespace instance (and in debug builds the leak is going to hit an // assertion failure when `WorkerThreadPrimaryRunnable::Run` calls the // assertion `MOZ_ASSERT(!globalScopeAlive)`, after that // `nsCycleCollector_shutdown()` has been called and we don't expect anything // to be keeping the service worker global scope alive). RefPtr mExtensionAlarms; RefPtr mExtensionBrowserSettings; RefPtr mExtensionDns; RefPtr mExtensionMockAPI; RefPtr mExtensionProxy; RefPtr mExtensionRuntime; RefPtr mExtensionScripting; RefPtr mExtensionTest; }; } // namespace extensions } // namespace mozilla #endif // mozilla_extensions_ExtensionBrowser_h