tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ServiceWorkerPrivate.h (15152B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_serviceworkerprivate_h
      8 #define mozilla_dom_serviceworkerprivate_h
      9 
     10 #include <functional>
     11 
     12 #include "mozilla/Attributes.h"
     13 #include "mozilla/Maybe.h"
     14 #include "mozilla/MozPromise.h"
     15 #include "mozilla/RefPtr.h"
     16 #include "mozilla/TimeStamp.h"
     17 #include "mozilla/UniquePtr.h"
     18 #include "mozilla/dom/FetchService.h"
     19 #include "mozilla/dom/Promise.h"
     20 #include "mozilla/dom/RemoteWorkerController.h"
     21 #include "mozilla/dom/RemoteWorkerTypes.h"
     22 #include "mozilla/dom/ServiceWorkerLifetimeExtension.h"
     23 #include "mozilla/dom/ServiceWorkerOpArgs.h"
     24 #include "nsCOMPtr.h"
     25 #include "nsISupportsImpl.h"
     26 #include "nsTArray.h"
     27 
     28 #define NOTIFICATION_CLICK_EVENT_NAME u"notificationclick"
     29 #define NOTIFICATION_CLOSE_EVENT_NAME u"notificationclose"
     30 
     31 class nsIInterceptedChannel;
     32 class nsIPushSubscription;
     33 class nsIWorkerDebugger;
     34 
     35 namespace mozilla {
     36 
     37 template <typename T>
     38 class Maybe;
     39 
     40 class JSObjectHolder;
     41 
     42 namespace net {
     43 class CookieStruct;
     44 }
     45 
     46 namespace dom {
     47 
     48 class PostMessageSource;
     49 class RemoteWorkerControllerChild;
     50 class ServiceWorkerCloneData;
     51 class ServiceWorkerInfo;
     52 class ServiceWorkerPrivate;
     53 class ServiceWorkerRegistrationInfo;
     54 struct CookieListItem;
     55 
     56 namespace ipc {
     57 class StructuredCloneData;
     58 }  // namespace ipc
     59 
     60 class LifeCycleEventCallback : public Runnable {
     61 public:
     62  LifeCycleEventCallback() : Runnable("dom::LifeCycleEventCallback") {}
     63 
     64  // Called on the worker thread.
     65  virtual void SetResult(bool aResult) = 0;
     66 };
     67 
     68 // Used to keep track of pending waitUntil as well as in-flight extendable
     69 // events. When the last token is released, we attempt to terminate the worker.
     70 class KeepAliveToken final : public nsISupports {
     71 public:
     72  NS_DECL_ISUPPORTS
     73 
     74  explicit KeepAliveToken(ServiceWorkerPrivate* aPrivate);
     75 
     76 private:
     77  ~KeepAliveToken();
     78 
     79  RefPtr<ServiceWorkerPrivate> mPrivate;
     80 };
     81 
     82 class ServiceWorkerPrivate final : public RemoteWorkerObserver {
     83  friend class KeepAliveToken;
     84 
     85 public:
     86  NS_INLINE_DECL_REFCOUNTING(ServiceWorkerPrivate, override);
     87 
     88  using PromiseExtensionWorkerHasListener = MozPromise<bool, nsresult, false>;
     89 
     90 public:
     91  explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo);
     92 
     93  Maybe<ClientInfo> GetClientInfo() { return mClientInfo; }
     94 
     95  nsresult SendMessageEvent(
     96      RefPtr<ServiceWorkerCloneData>&& aData,
     97      const ServiceWorkerLifetimeExtension& aLifetimeExtension,
     98      const PostMessageSource& aSource);
     99 
    100  // This is used to validate the worker script and continue the installation
    101  // process.
    102  nsresult CheckScriptEvaluation(
    103      const ServiceWorkerLifetimeExtension& aLifetimeExtension,
    104      RefPtr<LifeCycleEventCallback> aCallback);
    105 
    106  nsresult SendLifeCycleEvent(
    107      const nsAString& aEventType,
    108      const ServiceWorkerLifetimeExtension& aLifetimeExtension,
    109      const RefPtr<LifeCycleEventCallback>& aCallback);
    110 
    111  nsresult SendCookieChangeEvent(
    112      const net::CookieStruct& aCookie, bool aCookieDeleted,
    113      RefPtr<ServiceWorkerRegistrationInfo> aRegistration);
    114 
    115  nsresult SendPushEvent(const nsAString& aMessageId,
    116                         const Maybe<nsTArray<uint8_t>>& aData,
    117                         RefPtr<ServiceWorkerRegistrationInfo> aRegistration);
    118 
    119  nsresult SendPushSubscriptionChangeEvent(
    120      const RefPtr<nsIPushSubscription>& aOldSubscription);
    121 
    122  nsresult SendNotificationClickEvent(const IPCNotification& aNotification,
    123                                      const nsAString& aAction);
    124 
    125  nsresult SendNotificationCloseEvent(const IPCNotification& aNotification);
    126 
    127  nsresult SendFetchEvent(nsCOMPtr<nsIInterceptedChannel> aChannel,
    128                          nsILoadGroup* aLoadGroup, const nsAString& aClientId,
    129                          const nsAString& aResultingClientId);
    130 
    131  Result<RefPtr<PromiseExtensionWorkerHasListener>, nsresult>
    132  WakeForExtensionAPIEvent(const nsAString& aExtensionAPINamespace,
    133                           const nsAString& aEXtensionAPIEventName);
    134 
    135  // This will terminate the current running worker thread and drop the
    136  // workerPrivate reference.
    137  // Called by ServiceWorkerInfo when [[Clear Registration]] is invoked
    138  // or whenever the spec mandates that we terminate the worker.
    139  // This is a no-op if the worker has already been stopped.
    140  //
    141  // Now takes an optional promise that will be resolved when the worker is
    142  // dead, including if the worker was not running at all.
    143  void TerminateWorker(Maybe<RefPtr<Promise>> aMaybePromise = Nothing());
    144 
    145  void NoteDeadServiceWorkerInfo();
    146 
    147  void NoteStoppedControllingDocuments();
    148 
    149  void UpdateState(ServiceWorkerState aState);
    150 
    151  void UpdateIsOnContentBlockingAllowList(bool aOnContentBlockingAllowList);
    152 
    153  nsresult GetDebugger(nsIWorkerDebugger** aResult);
    154 
    155  nsresult AttachDebugger();
    156 
    157  nsresult DetachDebugger();
    158 
    159  // Return the current lifetime deadline for this ServiceWorker; this value may
    160  // be null or in the past.
    161  //
    162  // This value always only reflects the explicit lifetime extensions
    163  // resulting from functional events and will never reflect the extra "grace
    164  // period".
    165  TimeStamp GetLifetimeDeadline() { return mIdleDeadline; }
    166 
    167  uint32_t GetLaunchCount() { return mLaunchCount; }
    168 
    169  bool IsIdle() const;
    170 
    171  // This promise is used schedule clearing of the owning registrations and its
    172  // associated Service Workers if that registration becomes "unreachable" by
    173  // the ServiceWorkerManager. This occurs under two conditions, which are the
    174  // preconditions to calling this method:
    175  // - The owning registration must be unregistered.
    176  // - The associated Service Worker must *not* be controlling clients.
    177  //
    178  // Additionally, perhaps stating the obvious, the associated Service Worker
    179  // must *not* be idle (whatever must be done "when idle" can just be done
    180  // immediately).
    181  RefPtr<GenericPromise> GetIdlePromise();
    182 
    183  void SetHandlesFetch(bool aValue);
    184 
    185  RefPtr<GenericPromise> SetSkipWaitingFlag();
    186 
    187  static void RunningShutdown() {
    188    // Force a final update of the number of running ServiceWorkers
    189    UpdateRunning(0, 0);
    190    MOZ_ASSERT(sRunningServiceWorkers == 0);
    191    MOZ_ASSERT(sRunningServiceWorkersFetch == 0);
    192  }
    193 
    194  /**
    195   * Update Telemetry for # of running ServiceWorkers
    196   */
    197  static void UpdateRunning(int32_t aDelta, int32_t aFetchDelta);
    198 
    199 private:
    200  // Timer callbacks
    201  void NoteIdleWorkerCallback(nsITimer* aTimer);
    202 
    203  void TerminateWorkerCallback(nsITimer* aTimer);
    204 
    205  void RenewKeepAliveToken(
    206      const ServiceWorkerLifetimeExtension& aLifetimeExtension);
    207 
    208  void ResetIdleTimeout(
    209      const ServiceWorkerLifetimeExtension& aLifetimeExtension);
    210 
    211  void AddToken();
    212 
    213  void ReleaseToken();
    214 
    215  already_AddRefed<KeepAliveToken> CreateEventKeepAliveToken();
    216 
    217  nsresult SpawnWorkerIfNeeded(
    218      const ServiceWorkerLifetimeExtension& aLifetimeExtension);
    219 
    220  ~ServiceWorkerPrivate();
    221 
    222  nsresult Initialize();
    223 
    224  void RegenerateClientInfo();
    225 
    226  /**
    227   * RemoteWorkerObserver
    228   */
    229  void CreationFailed() override;
    230 
    231  void CreationSucceeded() override;
    232 
    233  void ErrorReceived(const ErrorValue& aError) override;
    234 
    235  void LockNotified(bool aCreated) final {
    236    // no-op for service workers
    237  }
    238 
    239  void WebTransportNotified(bool aCreated) final {
    240    // no-op for service workers
    241  }
    242 
    243  void Terminated() override;
    244 
    245  // Refreshes only the parts of mRemoteWorkerData that may change over time.
    246  void RefreshRemoteWorkerData(
    247      const RefPtr<ServiceWorkerRegistrationInfo>& aRegistration);
    248 
    249  nsresult SendCookieChangeEventInternal(
    250      RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
    251      ServiceWorkerCookieChangeEventOpArgs&& aArgs);
    252 
    253  nsresult SendPushEventInternal(
    254      RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
    255      ServiceWorkerPushEventOpArgs&& aArgs);
    256 
    257  // Setup the navigation preload by the intercepted channel and the
    258  // RegistrationInfo.
    259  RefPtr<FetchServicePromises> SetupNavigationPreload(
    260      nsCOMPtr<nsIInterceptedChannel>& aChannel,
    261      const RefPtr<ServiceWorkerRegistrationInfo>& aRegistration);
    262 
    263  nsresult SendFetchEventInternal(
    264      RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
    265      ParentToParentServiceWorkerFetchEventOpArgs&& aArgs,
    266      nsCOMPtr<nsIInterceptedChannel>&& aChannel,
    267      RefPtr<FetchServicePromises>&& aPreloadResponseReadyPromises);
    268 
    269  void Shutdown(Maybe<RefPtr<Promise>>&& aMaybePromise = Nothing());
    270 
    271  RefPtr<GenericNonExclusivePromise> ShutdownInternal(
    272      uint32_t aShutdownStateId);
    273 
    274  nsresult ExecServiceWorkerOp(
    275      ServiceWorkerOpArgs&& aArgs,
    276      const ServiceWorkerLifetimeExtension& aLifetimeExtension,
    277      std::function<void(ServiceWorkerOpResult&&)>&& aSuccessCallback,
    278      std::function<void()>&& aFailureCallback = [] {});
    279 
    280  class PendingFunctionalEvent {
    281   public:
    282    PendingFunctionalEvent(
    283        ServiceWorkerPrivate* aOwner,
    284        RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration);
    285 
    286    virtual ~PendingFunctionalEvent();
    287 
    288    virtual nsresult Send() = 0;
    289 
    290   protected:
    291    ServiceWorkerPrivate* const MOZ_NON_OWNING_REF mOwner;
    292    RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
    293  };
    294 
    295  class PendingCookieChangeEvent final : public PendingFunctionalEvent {
    296   public:
    297    PendingCookieChangeEvent(
    298        ServiceWorkerPrivate* aOwner,
    299        RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
    300        ServiceWorkerCookieChangeEventOpArgs&& aArgs);
    301 
    302    nsresult Send() override;
    303 
    304   private:
    305    ServiceWorkerCookieChangeEventOpArgs mArgs;
    306  };
    307 
    308  class PendingPushEvent final : public PendingFunctionalEvent {
    309   public:
    310    PendingPushEvent(ServiceWorkerPrivate* aOwner,
    311                     RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
    312                     ServiceWorkerPushEventOpArgs&& aArgs);
    313 
    314    nsresult Send() override;
    315 
    316   private:
    317    ServiceWorkerPushEventOpArgs mArgs;
    318  };
    319 
    320  class PendingFetchEvent final : public PendingFunctionalEvent {
    321   public:
    322    PendingFetchEvent(
    323        ServiceWorkerPrivate* aOwner,
    324        RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
    325        ParentToParentServiceWorkerFetchEventOpArgs&& aArgs,
    326        nsCOMPtr<nsIInterceptedChannel>&& aChannel,
    327        RefPtr<FetchServicePromises>&& aPreloadResponseReadyPromises);
    328 
    329    nsresult Send() override;
    330 
    331    ~PendingFetchEvent();
    332 
    333   private:
    334    ParentToParentServiceWorkerFetchEventOpArgs mArgs;
    335    nsCOMPtr<nsIInterceptedChannel> mChannel;
    336    // The promises from FetchService. It indicates if the preload response is
    337    // ready or not. The promise's resolve/reject value should be handled in
    338    // FetchEventOpChild, such that the preload result can be propagated to the
    339    // ServiceWorker through IPC. However, FetchEventOpChild creation could be
    340    // pending here, so this member is needed. And it will be forwarded to
    341    // FetchEventOpChild when crearting the FetchEventOpChild.
    342    RefPtr<FetchServicePromises> mPreloadResponseReadyPromises;
    343  };
    344 
    345  nsTArray<UniquePtr<PendingFunctionalEvent>> mPendingFunctionalEvents;
    346 
    347  /**
    348   * It's possible that there are still in-progress operations when a
    349   * a termination operation is issued. In this case, it's important to keep
    350   * the RemoteWorkerControllerChild actor alive until all pending operations
    351   * have completed before destroying it with Send__delete__().
    352   *
    353   * RAIIActorPtrHolder holds a singular, owning reference to a
    354   * RemoteWorkerControllerChild actor and is responsible for destroying the
    355   * actor in its (i.e. the holder's) destructor. This implies that all
    356   * in-progress operations must maintain a strong reference to their
    357   * corresponding holders and release the reference once completed/canceled.
    358   *
    359   * Additionally a RAIIActorPtrHolder must be initialized with a non-null actor
    360   * and cannot be moved or copied. Therefore, the identities of two held
    361   * actors can be compared by simply comparing their holders' addresses.
    362   */
    363  class RAIIActorPtrHolder final {
    364   public:
    365    NS_INLINE_DECL_REFCOUNTING(RAIIActorPtrHolder)
    366 
    367    explicit RAIIActorPtrHolder(
    368        already_AddRefed<RemoteWorkerControllerChild> aActor);
    369 
    370    RAIIActorPtrHolder(const RAIIActorPtrHolder& aOther) = delete;
    371    RAIIActorPtrHolder& operator=(const RAIIActorPtrHolder& aOther) = delete;
    372 
    373    RAIIActorPtrHolder(RAIIActorPtrHolder&& aOther) = delete;
    374    RAIIActorPtrHolder& operator=(RAIIActorPtrHolder&& aOther) = delete;
    375 
    376    RemoteWorkerControllerChild* operator->() const
    377        MOZ_NO_ADDREF_RELEASE_ON_RETURN;
    378 
    379    RemoteWorkerControllerChild* get() const;
    380 
    381    RefPtr<GenericPromise> OnDestructor();
    382 
    383   private:
    384    ~RAIIActorPtrHolder();
    385 
    386    MozPromiseHolder<GenericPromise> mDestructorPromiseHolder;
    387 
    388    const RefPtr<RemoteWorkerControllerChild> mActor;
    389  };
    390 
    391  RefPtr<RAIIActorPtrHolder> mControllerChild;
    392 
    393  RemoteWorkerData mRemoteWorkerData;
    394  Maybe<ClientInfo> mClientInfo;
    395 
    396  TimeStamp mServiceWorkerLaunchTimeStart;
    397 
    398  // Counters for Telemetry - totals running simultaneously, and those that
    399  // handle Fetch, plus Max values for each
    400  static uint32_t sRunningServiceWorkers;
    401  static uint32_t sRunningServiceWorkersFetch;
    402  static uint32_t sRunningServiceWorkersMax;
    403  static uint32_t sRunningServiceWorkersFetchMax;
    404 
    405  // We know the state after we've evaluated the worker, and we then store
    406  // it in the registration.  The only valid state transition should be
    407  // from Unknown to Enabled or Disabled.
    408  enum { Unknown, Enabled, Disabled } mHandlesFetch{Unknown};
    409 
    410  // The info object owns us. It is possible to outlive it for a brief period
    411  // of time if there are pending waitUntil promises, in which case it
    412  // will be null and |SpawnWorkerIfNeeded| will always fail.
    413  ServiceWorkerInfo* MOZ_NON_OWNING_REF mInfo;
    414 
    415  nsCOMPtr<nsITimer> mIdleWorkerTimer;
    416 
    417  ServiceWorkerLifetimeExtension mPendingSpawnLifetime;
    418 
    419  // This is the current time in the future that the idle timer is set to expire
    420  // for keepalive purposes.  This will not be updated for the
    421  // "dom.serviceWorkers.idle_extended_timeout" grace period after the time
    422  // first expires.
    423  TimeStamp mIdleDeadline;
    424 
    425  // We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the
    426  // worker a grace period after each event.
    427  RefPtr<KeepAliveToken> mIdleKeepAliveToken;
    428 
    429  uint64_t mDebuggerCount;
    430 
    431  uint64_t mTokenCount;
    432 
    433  uint32_t mLaunchCount;
    434 
    435  // Used by the owning `ServiceWorkerRegistrationInfo` when it wants to call
    436  // `Clear` after being unregistered and isn't controlling any clients but this
    437  // worker (i.e. the registration's active worker) isn't idle yet. Note that
    438  // such an event should happen at most once in a
    439  // `ServiceWorkerRegistrationInfo`s lifetime, so this promise should also only
    440  // be obtained at most once.
    441  MozPromiseHolder<GenericPromise> mIdlePromiseHolder;
    442 
    443 #ifdef DEBUG
    444  bool mIdlePromiseObtained = false;
    445 #endif
    446 };
    447 
    448 }  // namespace dom
    449 }  // namespace mozilla
    450 
    451 #endif  // mozilla_dom_serviceworkerprivate_h