123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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
|