diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /dom/workers/ServiceWorkerManager.h | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/workers/ServiceWorkerManager.h')
-rw-r--r-- | dom/workers/ServiceWorkerManager.h | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/dom/workers/ServiceWorkerManager.h b/dom/workers/ServiceWorkerManager.h new file mode 100644 index 000000000..f99bc4248 --- /dev/null +++ b/dom/workers/ServiceWorkerManager.h @@ -0,0 +1,521 @@ +/* -*- 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_workers_serviceworkermanager_h +#define mozilla_dom_workers_serviceworkermanager_h + +#include "nsIServiceWorkerManager.h" +#include "nsCOMPtr.h" + +#include "ipc/IPCMessageUtils.h" +#include "mozilla/Attributes.h" +#include "mozilla/AutoRestore.h" +#include "mozilla/ConsoleReportCollector.h" +#include "mozilla/LinkedList.h" +#include "mozilla/Preferences.h" +#include "mozilla/TypedEnumBits.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/WeakPtr.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/ServiceWorkerCommon.h" +#include "mozilla/dom/ServiceWorkerRegistrar.h" +#include "mozilla/dom/ServiceWorkerRegistrarTypes.h" +#include "mozilla/dom/workers/ServiceWorkerRegistrationInfo.h" +#include "mozilla/ipc/BackgroundUtils.h" +#include "nsClassHashtable.h" +#include "nsDataHashtable.h" +#include "nsIIPCBackgroundChildCreateCallback.h" +#include "nsRefPtrHashtable.h" +#include "nsTArrayForwardDeclare.h" +#include "nsTObserverArray.h" + +class mozIApplicationClearPrivateDataParams; +class nsIConsoleReportCollector; + +namespace mozilla { + +class PrincipalOriginAttributes; + +namespace dom { + +class ServiceWorkerRegistrar; +class ServiceWorkerRegistrationListener; + +namespace workers { + +class ServiceWorkerClientInfo; +class ServiceWorkerInfo; +class ServiceWorkerJobQueue; +class ServiceWorkerManagerChild; +class ServiceWorkerPrivate; + +class ServiceWorkerUpdateFinishCallback +{ +protected: + virtual ~ServiceWorkerUpdateFinishCallback() + {} + +public: + NS_INLINE_DECL_REFCOUNTING(ServiceWorkerUpdateFinishCallback) + + virtual + void UpdateSucceeded(ServiceWorkerRegistrationInfo* aInfo) = 0; + + virtual + void UpdateFailed(ErrorResult& aStatus) = 0; +}; + +#define NS_SERVICEWORKERMANAGER_IMPL_IID \ +{ /* f4f8755a-69ca-46e8-a65d-775745535990 */ \ + 0xf4f8755a, \ + 0x69ca, \ + 0x46e8, \ + { 0xa6, 0x5d, 0x77, 0x57, 0x45, 0x53, 0x59, 0x90 } \ +} + +/* + * The ServiceWorkerManager is a per-process global that deals with the + * installation, querying and event dispatch of ServiceWorkers for all the + * origins in the process. + */ +class ServiceWorkerManager final + : public nsIServiceWorkerManager + , public nsIIPCBackgroundChildCreateCallback + , public nsIObserver +{ + friend class GetReadyPromiseRunnable; + friend class GetRegistrationsRunnable; + friend class GetRegistrationRunnable; + friend class ServiceWorkerJob; + friend class ServiceWorkerRegistrationInfo; + friend class ServiceWorkerUnregisterJob; + friend class ServiceWorkerUpdateJob; + friend class UpdateTimerCallback; + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISERVICEWORKERMANAGER + NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK + NS_DECL_NSIOBSERVER + + struct RegistrationDataPerPrincipal; + nsClassHashtable<nsCStringHashKey, RegistrationDataPerPrincipal> mRegistrationInfos; + + nsTObserverArray<ServiceWorkerRegistrationListener*> mServiceWorkerRegistrationListeners; + + nsRefPtrHashtable<nsISupportsHashKey, ServiceWorkerRegistrationInfo> mControlledDocuments; + + // Track all documents that have attempted to register a service worker for a + // given scope. + typedef nsTArray<nsCOMPtr<nsIWeakReference>> WeakDocumentList; + nsClassHashtable<nsCStringHashKey, WeakDocumentList> mRegisteringDocuments; + + // Track all intercepted navigation channels for a given scope. Channels are + // placed in the appropriate list before dispatch the FetchEvent to the worker + // thread and removed once FetchEvent processing dispatches back to the main + // thread. + // + // Note: Its safe to use weak references here because a RAII-style callback + // is registered with the channel before its added to this list. We + // are guaranteed the callback will fire before and remove the ref + // from this list before the channel is destroyed. + typedef nsTArray<nsIInterceptedChannel*> InterceptionList; + nsClassHashtable<nsCStringHashKey, InterceptionList> mNavigationInterceptions; + + bool + IsAvailable(nsIPrincipal* aPrincipal, nsIURI* aURI); + + bool + IsControlled(nsIDocument* aDocument, ErrorResult& aRv); + + // Return true if the given content process could potentially be executing + // service worker code with the given principal. At the current time, this + // just means that we have any registration for the origin, regardless of + // scope. This is a very weak guarantee but is the best we can do when push + // notifications can currently spin up a service worker in content processes + // without our involvement in the parent process. + // + // In the future when there is only a single ServiceWorkerManager in the + // parent process that is entirely in control of spawning and running service + // worker code, we will be able to authoritatively indicate whether there is + // an activate service worker in the given content process. At that time we + // will rename this method HasActiveServiceWorkerInstance and provide + // semantics that ensure this method returns true until the worker is known to + // have shut down in order to allow the caller to induce a crash for security + // reasons without having to worry about shutdown races with the worker. + bool + MayHaveActiveServiceWorkerInstance(ContentParent* aContent, + nsIPrincipal* aPrincipal); + + void + DispatchFetchEvent(const PrincipalOriginAttributes& aOriginAttributes, + nsIDocument* aDoc, + const nsAString& aDocumentIdForTopLevelNavigation, + nsIInterceptedChannel* aChannel, + bool aIsReload, + bool aIsSubresourceLoad, + ErrorResult& aRv); + + void + Update(nsIPrincipal* aPrincipal, + const nsACString& aScope, + ServiceWorkerUpdateFinishCallback* aCallback); + + void + SoftUpdate(const PrincipalOriginAttributes& aOriginAttributes, + const nsACString& aScope); + + void + PropagateSoftUpdate(const PrincipalOriginAttributes& aOriginAttributes, + const nsAString& aScope); + + void + PropagateRemove(const nsACString& aHost); + + void + Remove(const nsACString& aHost); + + void + PropagateRemoveAll(); + + void + RemoveAll(); + + already_AddRefed<ServiceWorkerRegistrationInfo> + GetRegistration(nsIPrincipal* aPrincipal, const nsACString& aScope) const; + + already_AddRefed<ServiceWorkerRegistrationInfo> + CreateNewRegistration(const nsCString& aScope, nsIPrincipal* aPrincipal); + + void + RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration); + + void StoreRegistration(nsIPrincipal* aPrincipal, + ServiceWorkerRegistrationInfo* aRegistration); + + void + FinishFetch(ServiceWorkerRegistrationInfo* aRegistration); + + /** + * Report an error for the given scope to any window we think might be + * interested, failing over to the Browser Console if we couldn't find any. + * + * Error messages should be localized, so you probably want to call + * LocalizeAndReportToAllClients instead, which in turn calls us after + * localizing the error. + */ + void + ReportToAllClients(const nsCString& aScope, + const nsString& aMessage, + const nsString& aFilename, + const nsString& aLine, + uint32_t aLineNumber, + uint32_t aColumnNumber, + uint32_t aFlags); + + /** + * Report a localized error for the given scope to any window we think might + * be interested. + * + * Note that this method takes an nsTArray<nsString> for the parameters, not + * bare chart16_t*[]. You can use a std::initializer_list constructor inline + * so that argument might look like: nsTArray<nsString> { some_nsString, + * PromiseFlatString(some_nsSubString_aka_nsAString), + * NS_ConvertUTF8toUTF16(some_nsCString_or_nsCSubString), + * NS_LITERAL_STRING("some literal") }. If you have anything else, like a + * number, you can use an nsAutoString with AppendInt/friends. + * + * @param [aFlags] + * The nsIScriptError flag, one of errorFlag (0x0), warningFlag (0x1), + * infoFlag (0x8). We default to error if omitted because usually we're + * logging exceptional and/or obvious breakage. + */ + static void + LocalizeAndReportToAllClients(const nsCString& aScope, + const char* aStringKey, + const nsTArray<nsString>& aParamArray, + uint32_t aFlags = 0x0, + const nsString& aFilename = EmptyString(), + const nsString& aLine = EmptyString(), + uint32_t aLineNumber = 0, + uint32_t aColumnNumber = 0); + + void + FlushReportsToAllClients(const nsACString& aScope, + nsIConsoleReportCollector* aReporter); + + // Always consumes the error by reporting to consoles of all controlled + // documents. + void + HandleError(JSContext* aCx, + nsIPrincipal* aPrincipal, + const nsCString& aScope, + const nsString& aWorkerURL, + const nsString& aMessage, + const nsString& aFilename, + const nsString& aLine, + uint32_t aLineNumber, + uint32_t aColumnNumber, + uint32_t aFlags, + JSExnType aExnType); + + UniquePtr<ServiceWorkerClientInfo> + GetClient(nsIPrincipal* aPrincipal, + const nsAString& aClientId, + ErrorResult& aRv); + + void + GetAllClients(nsIPrincipal* aPrincipal, + const nsCString& aScope, + bool aIncludeUncontrolled, + nsTArray<ServiceWorkerClientInfo>& aDocuments); + + void + MaybeClaimClient(nsIDocument* aDocument, + ServiceWorkerRegistrationInfo* aWorkerRegistration); + + nsresult + ClaimClients(nsIPrincipal* aPrincipal, const nsCString& aScope, uint64_t aId); + + void + SetSkipWaitingFlag(nsIPrincipal* aPrincipal, const nsCString& aScope, + uint64_t aServiceWorkerID); + + static already_AddRefed<ServiceWorkerManager> + GetInstance(); + + void + LoadRegistration(const ServiceWorkerRegistrationData& aRegistration); + + void + LoadRegistrations(const nsTArray<ServiceWorkerRegistrationData>& aRegistrations); + + // Used by remove() and removeAll() when clearing history. + // MUST ONLY BE CALLED FROM UnregisterIfMatchesHost! + void + ForceUnregister(RegistrationDataPerPrincipal* aRegistrationData, + ServiceWorkerRegistrationInfo* aRegistration); + + NS_IMETHOD + AddRegistrationEventListener(const nsAString& aScope, + ServiceWorkerRegistrationListener* aListener); + + NS_IMETHOD + RemoveRegistrationEventListener(const nsAString& aScope, + ServiceWorkerRegistrationListener* aListener); + + void + MaybeCheckNavigationUpdate(nsIDocument* aDoc); + + nsresult + SendPushEvent(const nsACString& aOriginAttributes, + const nsACString& aScope, + const nsAString& aMessageId, + const Maybe<nsTArray<uint8_t>>& aData); + + nsresult + NotifyUnregister(nsIPrincipal* aPrincipal, const nsAString& aScope); + + void + WorkerIsIdle(ServiceWorkerInfo* aWorker); + +private: + ServiceWorkerManager(); + ~ServiceWorkerManager(); + + void + Init(ServiceWorkerRegistrar* aRegistrar); + + void + MaybeStartShutdown(); + + already_AddRefed<ServiceWorkerJobQueue> + GetOrCreateJobQueue(const nsACString& aOriginSuffix, + const nsACString& aScope); + + void + MaybeRemoveRegistrationInfo(const nsACString& aScopeKey); + + already_AddRefed<ServiceWorkerRegistrationInfo> + GetRegistration(const nsACString& aScopeKey, + const nsACString& aScope) const; + + void + AbortCurrentUpdate(ServiceWorkerRegistrationInfo* aRegistration); + + nsresult + Update(ServiceWorkerRegistrationInfo* aRegistration); + + nsresult + GetDocumentRegistration(nsIDocument* aDoc, + ServiceWorkerRegistrationInfo** aRegistrationInfo); + + nsresult + GetServiceWorkerForScope(nsPIDOMWindowInner* aWindow, + const nsAString& aScope, + WhichServiceWorker aWhichWorker, + nsISupports** aServiceWorker); + + ServiceWorkerInfo* + GetActiveWorkerInfoForScope(const PrincipalOriginAttributes& aOriginAttributes, + const nsACString& aScope); + + ServiceWorkerInfo* + GetActiveWorkerInfoForDocument(nsIDocument* aDocument); + + void + InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration, + WhichServiceWorker aWhichOnes); + + void + NotifyServiceWorkerRegistrationRemoved(ServiceWorkerRegistrationInfo* aRegistration); + + void + StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration, + nsIDocument* aDoc, + const nsAString& aDocumentId); + + void + StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration); + + already_AddRefed<ServiceWorkerRegistrationInfo> + GetServiceWorkerRegistrationInfo(nsPIDOMWindowInner* aWindow); + + already_AddRefed<ServiceWorkerRegistrationInfo> + GetServiceWorkerRegistrationInfo(nsIDocument* aDoc); + + already_AddRefed<ServiceWorkerRegistrationInfo> + GetServiceWorkerRegistrationInfo(nsIPrincipal* aPrincipal, nsIURI* aURI); + + already_AddRefed<ServiceWorkerRegistrationInfo> + GetServiceWorkerRegistrationInfo(const nsACString& aScopeKey, + nsIURI* aURI); + + // This method generates a key using appId and isInElementBrowser from the + // principal. We don't use the origin because it can change during the + // loading. + static nsresult + PrincipalToScopeKey(nsIPrincipal* aPrincipal, nsACString& aKey); + + static void + AddScopeAndRegistration(const nsACString& aScope, + ServiceWorkerRegistrationInfo* aRegistation); + + static bool + FindScopeForPath(const nsACString& aScopeKey, + const nsACString& aPath, + RegistrationDataPerPrincipal** aData, nsACString& aMatch); + + static bool + HasScope(nsIPrincipal* aPrincipal, const nsACString& aScope); + + static void + RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo* aRegistration); + + void + QueueFireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration, + const nsAString& aName); + + void + FireUpdateFoundOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration); + + void + FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration); + + void + StorePendingReadyPromise(nsPIDOMWindowInner* aWindow, nsIURI* aURI, + Promise* aPromise); + + void + CheckPendingReadyPromises(); + + bool + CheckReadyPromise(nsPIDOMWindowInner* aWindow, nsIURI* aURI, + Promise* aPromise); + + struct PendingReadyPromise final + { + PendingReadyPromise(nsIURI* aURI, Promise* aPromise) + : mURI(aURI), mPromise(aPromise) + {} + + nsCOMPtr<nsIURI> mURI; + RefPtr<Promise> mPromise; + }; + + void AppendPendingOperation(nsIRunnable* aRunnable); + + bool HasBackgroundActor() const + { + return !!mActor; + } + + nsClassHashtable<nsISupportsHashKey, PendingReadyPromise> mPendingReadyPromises; + + void + MaybeRemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration); + + // Removes all service worker registrations that matches the given pattern. + void + RemoveAllRegistrations(OriginAttributesPattern* aPattern); + + RefPtr<ServiceWorkerManagerChild> mActor; + + nsTArray<nsCOMPtr<nsIRunnable>> mPendingOperations; + + bool mShuttingDown; + + nsTArray<nsCOMPtr<nsIServiceWorkerManagerListener>> mListeners; + + void + NotifyListenersOnRegister(nsIServiceWorkerRegistrationInfo* aRegistration); + + void + NotifyListenersOnUnregister(nsIServiceWorkerRegistrationInfo* aRegistration); + + void + AddRegisteringDocument(const nsACString& aScope, nsIDocument* aDoc); + + class InterceptionReleaseHandle; + + void + AddNavigationInterception(const nsACString& aScope, + nsIInterceptedChannel* aChannel); + + void + RemoveNavigationInterception(const nsACString& aScope, + nsIInterceptedChannel* aChannel); + + void + ScheduleUpdateTimer(nsIPrincipal* aPrincipal, const nsACString& aScope); + + void + UpdateTimerFired(nsIPrincipal* aPrincipal, const nsACString& aScope); + + void + MaybeSendUnregister(nsIPrincipal* aPrincipal, const nsACString& aScope); + + nsresult + SendNotificationEvent(const nsAString& aEventName, + const nsACString& aOriginSuffix, + const nsACString& aScope, + const nsAString& aID, + const nsAString& aTitle, + const nsAString& aDir, + const nsAString& aLang, + const nsAString& aBody, + const nsAString& aTag, + const nsAString& aIcon, + const nsAString& aData, + const nsAString& aBehavior); +}; + +} // namespace workers +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_workers_serviceworkermanager_h |