gecko-dev/dom/serviceworkers/ServiceWorkerRegistrationInfo.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

275 lines
8.6 KiB
C
Raw Normal View History

/* -*- 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_serviceworkerregistrationinfo_h
#define mozilla_dom_serviceworkerregistrationinfo_h
#include <functional>
#include "mozilla/dom/IPCNavigationPreloadState.h"
#include "mozilla/dom/ServiceWorkerInfo.h"
Bug 1544232 - Limit lifetime extension of SWs by SWs to the sender's lifetime. r=edenchuang This patch introduces an explicit concept of lifetimes with mechanisms in place so that actions taken by Clients (windows or non-ServiceWorker orkers) will extend the lifetime of a ServiceWorker, but a ServiceWorker cannot extend the life of another ServiceWorker. The areas of concern are: - ServiceWorker.postMessage: With ServiceWorkers exposed on workers and the ability to access other registrations via ServiceWorkerContainer being exposed, ServiceWorkers can message other ServiceWorkers. It's essential that they never be allowed to give a ServiceWorker a lifetime longer than their own. - ServiceWorkerRegistration.update(): Requesting an update of a registration should not allow any installed/updated ServiceWorker to have a lifetime longer than the ServiceWorker creating the request. - ServiceWorkerContainer.register(): Requesting the installation of a new ServiceWorker should likewise constrain the lifetime of the newly installed ServiceWorker. Note that in cases where we would potentially spawn a ServiceWorker, whether it be in response to postMessage or as part of an install or update, a key criteria is whether the lifetime extends far enough into the future for us to believe the ServiceWorker can accomplish anything. Currently we have a constant of 5 seconds against a normal full lifetime of 30 seconds (before 30 second grace period). So once a SW has < 5 seconds of lifetime left, it won't be able to spawn a SW. Note that in the case of install/update, we do not prevent the creation of the job at this time, instead the job will fail during the check script evaluation step as failure to spawn the ServiceWorker is equivalent to a script load failure. A somewhat ugly part of this implementation is that because Bug 1853706 is not yet implemented, our actors that are fundamentally associated with a global don't have an inherent understanding of their relationship to that global. So we approximate that by: - For postMessage, we always have a ServiceWorkerDescriptor if we are being messaged by a ServiceWorker, allowing us direct lookup. - ServiceWorkerRegistration.update(): In a previous patch in the stack we had ServiceWorkerRegistrationProxy latch the ClientInfo of its owning global when it was created. Note that in the case of a ServiceWorker's own registration, this will be created at startup before the worker hits the execution ready state. - Note that because we have at most one live ServiceWorkerRegistration per global at a time, and the registration is fundamentally associated with the ServiceWorkerGlobalScope, that registration and its proxy will remain alive for the duration of the global. - ServiceWorkerContainer.register(): We already were sending the client info along with the register call (as well as all other calls on the container). Looking up the ServiceWorker from its client is not something that was really intended. This is further complicated by ServiceWorkerManager being authoritative for ServiceWorkers on the parent process main thread whereas the ClientManagerService is authoritative on PBackground and actor-centric, making sketchy multi-threaded maps not really an option. Looking up the ServiceWorker from a ServiceWorkerDescriptor is intended, but the primary intent in those cases is so that the recipient of such a descriptor can easily create a ServiceWorker instance that is live-updating (by way of its owning ServiceWorkerRegistration; we don't have IPC actors directly for ServiceWorkers, just the registration). Adding the descriptor to clients until Bug 1853706 is implemented would be an exceedingly ugly workaround because it would greatly complicate the existing plumbing code, and a lot of the code is confusing enough as-is. This patch initially adopted an approach of encoding the scope of a ServiceWorker as its client URL, but it turns out web extension ServiceWorker support (reasonably) assumed the URL would be the script URL so the original behavior was restored and when performing our lookup we just check all registrations associated with the given origin. This is okay because register and update calls are inherently expensive, rare operations and the overhead of the additional checks is marginal. Additionally, we can remove this logic once Bug 1853706 is implemented. As part of that initial scope tunneling was that, as noted above, we do sample the ClientInfo for a ServiceWorker's own registration before the worker is execution-ready. And prior to this patch, we only would populate the URL during execution-ready because for most globals, we can't possibly know the URL when the ClientSource is created. However, for ServiceWorkers we can. Because we also want to know what the id of the ServiceWorker client would be, we also change the creation of the ServiceWorker ClientSource so that it uses a ClientInfo created by the authoritative ServiceWorkerPrivate in its Initialize method. A minor retained hack is that because the worker scriptloader propagates its CSP structure onto its ClientInfo (but not its ClientSource, which feels weird, but makes sense) and that does get sent via register(), we do also need to normalize the ClientInfo in the parent when we do equality checking to have it ignore the CSP. Differential Revision: https://phabricator.services.mozilla.com/D180915
2024-10-24 03:02:42 +00:00
#include "mozilla/dom/ServiceWorkerLifetimeExtension.h"
#include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
#include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
#include "nsProxyRelease.h"
#include "nsTObserverArray.h"
namespace mozilla::dom {
class ServiceWorkerRegistrationListener;
class ServiceWorkerRegistrationInfo final
: public nsIServiceWorkerRegistrationInfo {
nsCOMPtr<nsIPrincipal> mPrincipal;
ServiceWorkerRegistrationDescriptor mDescriptor;
nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> mListeners;
nsTObserverArray<ServiceWorkerRegistrationListener*> mInstanceList;
struct VersionEntry {
const ServiceWorkerRegistrationDescriptor mDescriptor;
TimeStamp mTimeStamp;
explicit VersionEntry(
const ServiceWorkerRegistrationDescriptor& aDescriptor)
: mDescriptor(aDescriptor), mTimeStamp(TimeStamp::Now()) {}
};
nsTArray<UniquePtr<VersionEntry>> mVersionList;
const nsID mAgentClusterId = nsID::GenerateUUID();
uint32_t mControlledClientsCounter;
uint32_t mDelayMultiplier;
enum { NoUpdate, NeedTimeCheckAndUpdate, NeedUpdate } mUpdateState;
// Timestamp to track SWR's last update time
PRTime mCreationTime;
TimeStamp mCreationTimeStamp;
// The time of update is 0, if SWR've never been updated yet.
PRTime mLastUpdateTime;
RefPtr<ServiceWorkerInfo> mEvaluatingWorker;
RefPtr<ServiceWorkerInfo> mActiveWorker;
RefPtr<ServiceWorkerInfo> mWaitingWorker;
RefPtr<ServiceWorkerInfo> mInstallingWorker;
virtual ~ServiceWorkerRegistrationInfo();
// When unregister() is called on a registration, it is removed from the
// "scope to registration map" but not immediately "cleared" (i.e. its workers
// terminated, updated to the redundant state, etc.) because it may still be
// controlling clients. It is marked as unregistered and when all controlled
// clients go away, cleared. This way we can tell if a registration
// is unregistered by querying the object itself rather than incurring a table
// lookup (in the case when the registrations are passed around as pointers).
bool mUnregistered;
bool mCorrupt;
IPCNavigationPreloadState mNavigationPreloadState;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISERVICEWORKERREGISTRATIONINFO
using TryToActivateCallback = std::function<void()>;
ServiceWorkerRegistrationInfo(
const nsACString& aScope, nsIPrincipal* aPrincipal,
ServiceWorkerUpdateViaCache aUpdateViaCache,
IPCNavigationPreloadState&& aNavigationPreloadState);
void AddInstance(ServiceWorkerRegistrationListener* aInstance,
const ServiceWorkerRegistrationDescriptor& aDescriptor);
void RemoveInstance(ServiceWorkerRegistrationListener* aInstance);
const nsCString& Scope() const;
nsIPrincipal* Principal() const;
bool IsUnregistered() const;
void SetUnregistered();
already_AddRefed<ServiceWorkerInfo> Newest() const {
RefPtr<ServiceWorkerInfo> newest;
if (mInstallingWorker) {
newest = mInstallingWorker;
} else if (mWaitingWorker) {
newest = mWaitingWorker;
} else {
newest = mActiveWorker;
}
return newest.forget();
}
already_AddRefed<ServiceWorkerInfo> NewestIncludingEvaluating() const {
if (mEvaluatingWorker) {
RefPtr<ServiceWorkerInfo> newest = mEvaluatingWorker;
return newest.forget();
}
return Newest();
}
already_AddRefed<ServiceWorkerInfo> GetServiceWorkerInfoById(uint64_t aId);
void StartControllingClient() {
++mControlledClientsCounter;
mDelayMultiplier = 0;
}
void StopControllingClient() {
MOZ_ASSERT(mControlledClientsCounter);
--mControlledClientsCounter;
}
bool IsControllingClients() const {
return mActiveWorker && mControlledClientsCounter;
}
// As a side effect, this nullifies
// `m{Evaluating,Installing,Waiting,Active}Worker`s.
void ShutdownWorkers();
void Clear();
void ClearAsCorrupt();
bool IsCorrupt() const;
Bug 1544232 - Limit lifetime extension of SWs by SWs to the sender's lifetime. r=edenchuang This patch introduces an explicit concept of lifetimes with mechanisms in place so that actions taken by Clients (windows or non-ServiceWorker orkers) will extend the lifetime of a ServiceWorker, but a ServiceWorker cannot extend the life of another ServiceWorker. The areas of concern are: - ServiceWorker.postMessage: With ServiceWorkers exposed on workers and the ability to access other registrations via ServiceWorkerContainer being exposed, ServiceWorkers can message other ServiceWorkers. It's essential that they never be allowed to give a ServiceWorker a lifetime longer than their own. - ServiceWorkerRegistration.update(): Requesting an update of a registration should not allow any installed/updated ServiceWorker to have a lifetime longer than the ServiceWorker creating the request. - ServiceWorkerContainer.register(): Requesting the installation of a new ServiceWorker should likewise constrain the lifetime of the newly installed ServiceWorker. Note that in cases where we would potentially spawn a ServiceWorker, whether it be in response to postMessage or as part of an install or update, a key criteria is whether the lifetime extends far enough into the future for us to believe the ServiceWorker can accomplish anything. Currently we have a constant of 5 seconds against a normal full lifetime of 30 seconds (before 30 second grace period). So once a SW has < 5 seconds of lifetime left, it won't be able to spawn a SW. Note that in the case of install/update, we do not prevent the creation of the job at this time, instead the job will fail during the check script evaluation step as failure to spawn the ServiceWorker is equivalent to a script load failure. A somewhat ugly part of this implementation is that because Bug 1853706 is not yet implemented, our actors that are fundamentally associated with a global don't have an inherent understanding of their relationship to that global. So we approximate that by: - For postMessage, we always have a ServiceWorkerDescriptor if we are being messaged by a ServiceWorker, allowing us direct lookup. - ServiceWorkerRegistration.update(): In a previous patch in the stack we had ServiceWorkerRegistrationProxy latch the ClientInfo of its owning global when it was created. Note that in the case of a ServiceWorker's own registration, this will be created at startup before the worker hits the execution ready state. - Note that because we have at most one live ServiceWorkerRegistration per global at a time, and the registration is fundamentally associated with the ServiceWorkerGlobalScope, that registration and its proxy will remain alive for the duration of the global. - ServiceWorkerContainer.register(): We already were sending the client info along with the register call (as well as all other calls on the container). Looking up the ServiceWorker from its client is not something that was really intended. This is further complicated by ServiceWorkerManager being authoritative for ServiceWorkers on the parent process main thread whereas the ClientManagerService is authoritative on PBackground and actor-centric, making sketchy multi-threaded maps not really an option. Looking up the ServiceWorker from a ServiceWorkerDescriptor is intended, but the primary intent in those cases is so that the recipient of such a descriptor can easily create a ServiceWorker instance that is live-updating (by way of its owning ServiceWorkerRegistration; we don't have IPC actors directly for ServiceWorkers, just the registration). Adding the descriptor to clients until Bug 1853706 is implemented would be an exceedingly ugly workaround because it would greatly complicate the existing plumbing code, and a lot of the code is confusing enough as-is. This patch initially adopted an approach of encoding the scope of a ServiceWorker as its client URL, but it turns out web extension ServiceWorker support (reasonably) assumed the URL would be the script URL so the original behavior was restored and when performing our lookup we just check all registrations associated with the given origin. This is okay because register and update calls are inherently expensive, rare operations and the overhead of the additional checks is marginal. Additionally, we can remove this logic once Bug 1853706 is implemented. As part of that initial scope tunneling was that, as noted above, we do sample the ClientInfo for a ServiceWorker's own registration before the worker is execution-ready. And prior to this patch, we only would populate the URL during execution-ready because for most globals, we can't possibly know the URL when the ClientSource is created. However, for ServiceWorkers we can. Because we also want to know what the id of the ServiceWorker client would be, we also change the creation of the ServiceWorker ClientSource so that it uses a ClientInfo created by the authoritative ServiceWorkerPrivate in its Initialize method. A minor retained hack is that because the worker scriptloader propagates its CSP structure onto its ClientInfo (but not its ClientSource, which feels weird, but makes sense) and that does get sent via register(), we do also need to normalize the ClientInfo in the parent when we do equality checking to have it ignore the CSP. Differential Revision: https://phabricator.services.mozilla.com/D180915
2024-10-24 03:02:42 +00:00
void TryToActivateAsync(
const ServiceWorkerLifetimeExtension& aLifetimeExtension,
TryToActivateCallback&& aCallback = nullptr);
Bug 1544232 - Limit lifetime extension of SWs by SWs to the sender's lifetime. r=edenchuang This patch introduces an explicit concept of lifetimes with mechanisms in place so that actions taken by Clients (windows or non-ServiceWorker orkers) will extend the lifetime of a ServiceWorker, but a ServiceWorker cannot extend the life of another ServiceWorker. The areas of concern are: - ServiceWorker.postMessage: With ServiceWorkers exposed on workers and the ability to access other registrations via ServiceWorkerContainer being exposed, ServiceWorkers can message other ServiceWorkers. It's essential that they never be allowed to give a ServiceWorker a lifetime longer than their own. - ServiceWorkerRegistration.update(): Requesting an update of a registration should not allow any installed/updated ServiceWorker to have a lifetime longer than the ServiceWorker creating the request. - ServiceWorkerContainer.register(): Requesting the installation of a new ServiceWorker should likewise constrain the lifetime of the newly installed ServiceWorker. Note that in cases where we would potentially spawn a ServiceWorker, whether it be in response to postMessage or as part of an install or update, a key criteria is whether the lifetime extends far enough into the future for us to believe the ServiceWorker can accomplish anything. Currently we have a constant of 5 seconds against a normal full lifetime of 30 seconds (before 30 second grace period). So once a SW has < 5 seconds of lifetime left, it won't be able to spawn a SW. Note that in the case of install/update, we do not prevent the creation of the job at this time, instead the job will fail during the check script evaluation step as failure to spawn the ServiceWorker is equivalent to a script load failure. A somewhat ugly part of this implementation is that because Bug 1853706 is not yet implemented, our actors that are fundamentally associated with a global don't have an inherent understanding of their relationship to that global. So we approximate that by: - For postMessage, we always have a ServiceWorkerDescriptor if we are being messaged by a ServiceWorker, allowing us direct lookup. - ServiceWorkerRegistration.update(): In a previous patch in the stack we had ServiceWorkerRegistrationProxy latch the ClientInfo of its owning global when it was created. Note that in the case of a ServiceWorker's own registration, this will be created at startup before the worker hits the execution ready state. - Note that because we have at most one live ServiceWorkerRegistration per global at a time, and the registration is fundamentally associated with the ServiceWorkerGlobalScope, that registration and its proxy will remain alive for the duration of the global. - ServiceWorkerContainer.register(): We already were sending the client info along with the register call (as well as all other calls on the container). Looking up the ServiceWorker from its client is not something that was really intended. This is further complicated by ServiceWorkerManager being authoritative for ServiceWorkers on the parent process main thread whereas the ClientManagerService is authoritative on PBackground and actor-centric, making sketchy multi-threaded maps not really an option. Looking up the ServiceWorker from a ServiceWorkerDescriptor is intended, but the primary intent in those cases is so that the recipient of such a descriptor can easily create a ServiceWorker instance that is live-updating (by way of its owning ServiceWorkerRegistration; we don't have IPC actors directly for ServiceWorkers, just the registration). Adding the descriptor to clients until Bug 1853706 is implemented would be an exceedingly ugly workaround because it would greatly complicate the existing plumbing code, and a lot of the code is confusing enough as-is. This patch initially adopted an approach of encoding the scope of a ServiceWorker as its client URL, but it turns out web extension ServiceWorker support (reasonably) assumed the URL would be the script URL so the original behavior was restored and when performing our lookup we just check all registrations associated with the given origin. This is okay because register and update calls are inherently expensive, rare operations and the overhead of the additional checks is marginal. Additionally, we can remove this logic once Bug 1853706 is implemented. As part of that initial scope tunneling was that, as noted above, we do sample the ClientInfo for a ServiceWorker's own registration before the worker is execution-ready. And prior to this patch, we only would populate the URL during execution-ready because for most globals, we can't possibly know the URL when the ClientSource is created. However, for ServiceWorkers we can. Because we also want to know what the id of the ServiceWorker client would be, we also change the creation of the ServiceWorker ClientSource so that it uses a ClientInfo created by the authoritative ServiceWorkerPrivate in its Initialize method. A minor retained hack is that because the worker scriptloader propagates its CSP structure onto its ClientInfo (but not its ClientSource, which feels weird, but makes sense) and that does get sent via register(), we do also need to normalize the ClientInfo in the parent when we do equality checking to have it ignore the CSP. Differential Revision: https://phabricator.services.mozilla.com/D180915
2024-10-24 03:02:42 +00:00
void TryToActivate(ServiceWorkerLifetimeExtension&& aLifetimeExtension,
TryToActivateCallback&& aCallback);
Bug 1544232 - Limit lifetime extension of SWs by SWs to the sender's lifetime. r=edenchuang This patch introduces an explicit concept of lifetimes with mechanisms in place so that actions taken by Clients (windows or non-ServiceWorker orkers) will extend the lifetime of a ServiceWorker, but a ServiceWorker cannot extend the life of another ServiceWorker. The areas of concern are: - ServiceWorker.postMessage: With ServiceWorkers exposed on workers and the ability to access other registrations via ServiceWorkerContainer being exposed, ServiceWorkers can message other ServiceWorkers. It's essential that they never be allowed to give a ServiceWorker a lifetime longer than their own. - ServiceWorkerRegistration.update(): Requesting an update of a registration should not allow any installed/updated ServiceWorker to have a lifetime longer than the ServiceWorker creating the request. - ServiceWorkerContainer.register(): Requesting the installation of a new ServiceWorker should likewise constrain the lifetime of the newly installed ServiceWorker. Note that in cases where we would potentially spawn a ServiceWorker, whether it be in response to postMessage or as part of an install or update, a key criteria is whether the lifetime extends far enough into the future for us to believe the ServiceWorker can accomplish anything. Currently we have a constant of 5 seconds against a normal full lifetime of 30 seconds (before 30 second grace period). So once a SW has < 5 seconds of lifetime left, it won't be able to spawn a SW. Note that in the case of install/update, we do not prevent the creation of the job at this time, instead the job will fail during the check script evaluation step as failure to spawn the ServiceWorker is equivalent to a script load failure. A somewhat ugly part of this implementation is that because Bug 1853706 is not yet implemented, our actors that are fundamentally associated with a global don't have an inherent understanding of their relationship to that global. So we approximate that by: - For postMessage, we always have a ServiceWorkerDescriptor if we are being messaged by a ServiceWorker, allowing us direct lookup. - ServiceWorkerRegistration.update(): In a previous patch in the stack we had ServiceWorkerRegistrationProxy latch the ClientInfo of its owning global when it was created. Note that in the case of a ServiceWorker's own registration, this will be created at startup before the worker hits the execution ready state. - Note that because we have at most one live ServiceWorkerRegistration per global at a time, and the registration is fundamentally associated with the ServiceWorkerGlobalScope, that registration and its proxy will remain alive for the duration of the global. - ServiceWorkerContainer.register(): We already were sending the client info along with the register call (as well as all other calls on the container). Looking up the ServiceWorker from its client is not something that was really intended. This is further complicated by ServiceWorkerManager being authoritative for ServiceWorkers on the parent process main thread whereas the ClientManagerService is authoritative on PBackground and actor-centric, making sketchy multi-threaded maps not really an option. Looking up the ServiceWorker from a ServiceWorkerDescriptor is intended, but the primary intent in those cases is so that the recipient of such a descriptor can easily create a ServiceWorker instance that is live-updating (by way of its owning ServiceWorkerRegistration; we don't have IPC actors directly for ServiceWorkers, just the registration). Adding the descriptor to clients until Bug 1853706 is implemented would be an exceedingly ugly workaround because it would greatly complicate the existing plumbing code, and a lot of the code is confusing enough as-is. This patch initially adopted an approach of encoding the scope of a ServiceWorker as its client URL, but it turns out web extension ServiceWorker support (reasonably) assumed the URL would be the script URL so the original behavior was restored and when performing our lookup we just check all registrations associated with the given origin. This is okay because register and update calls are inherently expensive, rare operations and the overhead of the additional checks is marginal. Additionally, we can remove this logic once Bug 1853706 is implemented. As part of that initial scope tunneling was that, as noted above, we do sample the ClientInfo for a ServiceWorker's own registration before the worker is execution-ready. And prior to this patch, we only would populate the URL during execution-ready because for most globals, we can't possibly know the URL when the ClientSource is created. However, for ServiceWorkers we can. Because we also want to know what the id of the ServiceWorker client would be, we also change the creation of the ServiceWorker ClientSource so that it uses a ClientInfo created by the authoritative ServiceWorkerPrivate in its Initialize method. A minor retained hack is that because the worker scriptloader propagates its CSP structure onto its ClientInfo (but not its ClientSource, which feels weird, but makes sense) and that does get sent via register(), we do also need to normalize the ClientInfo in the parent when we do equality checking to have it ignore the CSP. Differential Revision: https://phabricator.services.mozilla.com/D180915
2024-10-24 03:02:42 +00:00
void Activate(const ServiceWorkerLifetimeExtension& aLifetimeExtension);
void FinishActivate(bool aSuccess);
void RefreshLastUpdateCheckTime();
bool IsLastUpdateCheckTimeOverOneDay() const;
void MaybeScheduleTimeCheckAndUpdate();
void MaybeScheduleUpdate();
bool CheckAndClearIfUpdateNeeded();
ServiceWorkerInfo* GetEvaluating() const;
ServiceWorkerInfo* GetInstalling() const;
ServiceWorkerInfo* GetWaiting() const;
ServiceWorkerInfo* GetActive() const;
ServiceWorkerInfo* GetByDescriptor(
const ServiceWorkerDescriptor& aDescriptor) const;
Bug 1544232 - Limit lifetime extension of SWs by SWs to the sender's lifetime. r=edenchuang This patch introduces an explicit concept of lifetimes with mechanisms in place so that actions taken by Clients (windows or non-ServiceWorker orkers) will extend the lifetime of a ServiceWorker, but a ServiceWorker cannot extend the life of another ServiceWorker. The areas of concern are: - ServiceWorker.postMessage: With ServiceWorkers exposed on workers and the ability to access other registrations via ServiceWorkerContainer being exposed, ServiceWorkers can message other ServiceWorkers. It's essential that they never be allowed to give a ServiceWorker a lifetime longer than their own. - ServiceWorkerRegistration.update(): Requesting an update of a registration should not allow any installed/updated ServiceWorker to have a lifetime longer than the ServiceWorker creating the request. - ServiceWorkerContainer.register(): Requesting the installation of a new ServiceWorker should likewise constrain the lifetime of the newly installed ServiceWorker. Note that in cases where we would potentially spawn a ServiceWorker, whether it be in response to postMessage or as part of an install or update, a key criteria is whether the lifetime extends far enough into the future for us to believe the ServiceWorker can accomplish anything. Currently we have a constant of 5 seconds against a normal full lifetime of 30 seconds (before 30 second grace period). So once a SW has < 5 seconds of lifetime left, it won't be able to spawn a SW. Note that in the case of install/update, we do not prevent the creation of the job at this time, instead the job will fail during the check script evaluation step as failure to spawn the ServiceWorker is equivalent to a script load failure. A somewhat ugly part of this implementation is that because Bug 1853706 is not yet implemented, our actors that are fundamentally associated with a global don't have an inherent understanding of their relationship to that global. So we approximate that by: - For postMessage, we always have a ServiceWorkerDescriptor if we are being messaged by a ServiceWorker, allowing us direct lookup. - ServiceWorkerRegistration.update(): In a previous patch in the stack we had ServiceWorkerRegistrationProxy latch the ClientInfo of its owning global when it was created. Note that in the case of a ServiceWorker's own registration, this will be created at startup before the worker hits the execution ready state. - Note that because we have at most one live ServiceWorkerRegistration per global at a time, and the registration is fundamentally associated with the ServiceWorkerGlobalScope, that registration and its proxy will remain alive for the duration of the global. - ServiceWorkerContainer.register(): We already were sending the client info along with the register call (as well as all other calls on the container). Looking up the ServiceWorker from its client is not something that was really intended. This is further complicated by ServiceWorkerManager being authoritative for ServiceWorkers on the parent process main thread whereas the ClientManagerService is authoritative on PBackground and actor-centric, making sketchy multi-threaded maps not really an option. Looking up the ServiceWorker from a ServiceWorkerDescriptor is intended, but the primary intent in those cases is so that the recipient of such a descriptor can easily create a ServiceWorker instance that is live-updating (by way of its owning ServiceWorkerRegistration; we don't have IPC actors directly for ServiceWorkers, just the registration). Adding the descriptor to clients until Bug 1853706 is implemented would be an exceedingly ugly workaround because it would greatly complicate the existing plumbing code, and a lot of the code is confusing enough as-is. This patch initially adopted an approach of encoding the scope of a ServiceWorker as its client URL, but it turns out web extension ServiceWorker support (reasonably) assumed the URL would be the script URL so the original behavior was restored and when performing our lookup we just check all registrations associated with the given origin. This is okay because register and update calls are inherently expensive, rare operations and the overhead of the additional checks is marginal. Additionally, we can remove this logic once Bug 1853706 is implemented. As part of that initial scope tunneling was that, as noted above, we do sample the ClientInfo for a ServiceWorker's own registration before the worker is execution-ready. And prior to this patch, we only would populate the URL during execution-ready because for most globals, we can't possibly know the URL when the ClientSource is created. However, for ServiceWorkers we can. Because we also want to know what the id of the ServiceWorker client would be, we also change the creation of the ServiceWorker ClientSource so that it uses a ClientInfo created by the authoritative ServiceWorkerPrivate in its Initialize method. A minor retained hack is that because the worker scriptloader propagates its CSP structure onto its ClientInfo (but not its ClientSource, which feels weird, but makes sense) and that does get sent via register(), we do also need to normalize the ClientInfo in the parent when we do equality checking to have it ignore the CSP. Differential Revision: https://phabricator.services.mozilla.com/D180915
2024-10-24 03:02:42 +00:00
ServiceWorkerInfo* GetByClientInfo(const ClientInfo& aClientInfo) const;
// Set the given worker as the evaluating service worker. The worker
// state is not changed.
void SetEvaluating(ServiceWorkerInfo* aServiceWorker);
// Remove an existing evaluating worker, if present. The worker will
// be transitioned to the Redundant state.
void ClearEvaluating();
// Remove an existing installing worker, if present. The worker will
// be transitioned to the Redundant state.
void ClearInstalling();
// Transition the current evaluating worker to be the installing worker. The
// worker's state is update to Installing.
void TransitionEvaluatingToInstalling();
// Transition the current installing worker to be the waiting worker. The
// worker's state is updated to Installed.
void TransitionInstallingToWaiting();
// Override the current active worker. This is used during browser
// initialization to load persisted workers. Its also used to propagate
// active workers across child processes in e10s. This second use will
// go away once the ServiceWorkerManager moves to the parent process.
// The worker is transitioned to the Activated state.
void SetActive(ServiceWorkerInfo* aServiceWorker);
// Transition the current waiting worker to be the new active worker. The
// worker is updated to the Activating state.
void TransitionWaitingToActive();
// Determine if the registration is actively performing work.
bool IsIdle() const;
ServiceWorkerUpdateViaCache GetUpdateViaCache() const;
void SetUpdateViaCache(ServiceWorkerUpdateViaCache aUpdateViaCache);
int64_t GetLastUpdateTime() const;
void SetLastUpdateTime(const int64_t aTime);
const ServiceWorkerRegistrationDescriptor& Descriptor() const;
uint64_t Id() const;
uint64_t Version() const;
uint32_t GetUpdateDelay(const bool aWithMultiplier = true);
void FireUpdateFound();
void NotifyCleared();
void ClearWhenIdle();
const nsID& AgentClusterId() const;
void SetNavigationPreloadEnabled(const bool& aEnabled);
void SetNavigationPreloadHeader(const nsCString& aHeader);
IPCNavigationPreloadState GetNavigationPreloadState() const;
private:
// Roughly equivalent to [[Update Registration State algorithm]]. Make sure
// this is called *before* updating SW instances' state, otherwise they
// may get CC-ed.
void UpdateRegistrationState();
void UpdateRegistrationState(ServiceWorkerUpdateViaCache aUpdateViaCache);
// Used by devtools to track changes to the properties of
// *nsIServiceWorkerRegistrationInfo*. Note, this doesn't necessarily need to
// be in sync with the DOM registration objects, but it does need to be called
// in the same task that changed |mInstallingWorker|, |mWaitingWorker| or
// |mActiveWorker|.
void NotifyChromeRegistrationListeners();
static uint64_t GetNextId();
static uint64_t GetNextVersion();
// `aFunc`'s argument will be a reference to
// `m{Evaluating,Installing,Waiting,Active}Worker` (not to copy of them).
// Additionally, a null check will be performed for each worker before each
// call to `aFunc`, so `aFunc` will always get a reference to a non-null
// pointer.
void ForEachWorker(void (*aFunc)(RefPtr<ServiceWorkerInfo>&));
void CheckQuotaUsage();
};
} // namespace mozilla::dom
#endif // mozilla_dom_serviceworkerregistrationinfo_h