tor-browser

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

ServiceWorkerInfo.cpp (11509B)


      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 #include "ServiceWorkerInfo.h"
      8 
      9 #include "ServiceWorkerManager.h"
     10 #include "ServiceWorkerPrivate.h"
     11 #include "ServiceWorkerScriptCache.h"
     12 #include "ServiceWorkerUtils.h"
     13 #include "mozilla/dom/ClientIPCTypes.h"
     14 #include "mozilla/dom/ClientState.h"
     15 #include "mozilla/dom/Promise.h"
     16 #include "mozilla/dom/RemoteWorkerTypes.h"
     17 #include "mozilla/dom/WorkerPrivate.h"
     18 
     19 namespace mozilla::dom {
     20 
     21 using mozilla::ipc::PrincipalInfo;
     22 
     23 static_assert(nsIServiceWorkerInfo::STATE_PARSED ==
     24                  static_cast<uint16_t>(ServiceWorkerState::Parsed),
     25              "ServiceWorkerState enumeration value should match state values "
     26              "from nsIServiceWorkerInfo.");
     27 static_assert(nsIServiceWorkerInfo::STATE_INSTALLING ==
     28                  static_cast<uint16_t>(ServiceWorkerState::Installing),
     29              "ServiceWorkerState enumeration value should match state values "
     30              "from nsIServiceWorkerInfo.");
     31 static_assert(nsIServiceWorkerInfo::STATE_INSTALLED ==
     32                  static_cast<uint16_t>(ServiceWorkerState::Installed),
     33              "ServiceWorkerState enumeration value should match state values "
     34              "from nsIServiceWorkerInfo.");
     35 static_assert(nsIServiceWorkerInfo::STATE_ACTIVATING ==
     36                  static_cast<uint16_t>(ServiceWorkerState::Activating),
     37              "ServiceWorkerState enumeration value should match state values "
     38              "from nsIServiceWorkerInfo.");
     39 static_assert(nsIServiceWorkerInfo::STATE_ACTIVATED ==
     40                  static_cast<uint16_t>(ServiceWorkerState::Activated),
     41              "ServiceWorkerState enumeration value should match state values "
     42              "from nsIServiceWorkerInfo.");
     43 static_assert(nsIServiceWorkerInfo::STATE_REDUNDANT ==
     44                  static_cast<uint16_t>(ServiceWorkerState::Redundant),
     45              "ServiceWorkerState enumeration value should match state values "
     46              "from nsIServiceWorkerInfo.");
     47 static_assert(nsIServiceWorkerInfo::STATE_UNKNOWN ==
     48                  ContiguousEnumSize<ServiceWorkerState>::value,
     49              "ServiceWorkerState enumeration value should match state values "
     50              "from nsIServiceWorkerInfo.");
     51 
     52 NS_IMPL_ISUPPORTS(ServiceWorkerInfo, nsIServiceWorkerInfo)
     53 
     54 NS_IMETHODIMP
     55 ServiceWorkerInfo::GetId(nsAString& aId) {
     56  MOZ_ASSERT(NS_IsMainThread());
     57  aId = mWorkerPrivateId;
     58  return NS_OK;
     59 }
     60 
     61 NS_IMETHODIMP
     62 ServiceWorkerInfo::GetScriptSpec(nsAString& aScriptSpec) {
     63  MOZ_ASSERT(NS_IsMainThread());
     64  CopyUTF8toUTF16(mDescriptor.ScriptURL(), aScriptSpec);
     65  return NS_OK;
     66 }
     67 
     68 NS_IMETHODIMP
     69 ServiceWorkerInfo::GetCacheName(nsAString& aCacheName) {
     70  MOZ_ASSERT(NS_IsMainThread());
     71  aCacheName = mCacheName;
     72  return NS_OK;
     73 }
     74 
     75 NS_IMETHODIMP
     76 ServiceWorkerInfo::GetLaunchCount(uint32_t* aLaunchCount) {
     77  MOZ_ASSERT(aLaunchCount);
     78  MOZ_ASSERT(NS_IsMainThread());
     79  *aLaunchCount = mServiceWorkerPrivate->GetLaunchCount();
     80  return NS_OK;
     81 }
     82 
     83 NS_IMETHODIMP
     84 ServiceWorkerInfo::GetState(uint16_t* aState) {
     85  MOZ_ASSERT(aState);
     86  MOZ_ASSERT(NS_IsMainThread());
     87  *aState = static_cast<uint16_t>(State());
     88  return NS_OK;
     89 }
     90 
     91 NS_IMETHODIMP
     92 ServiceWorkerInfo::GetDebugger(nsIWorkerDebugger** aResult) {
     93  if (NS_WARN_IF(!aResult)) {
     94    return NS_ERROR_FAILURE;
     95  }
     96 
     97  return mServiceWorkerPrivate->GetDebugger(aResult);
     98 }
     99 
    100 NS_IMETHODIMP
    101 ServiceWorkerInfo::GetHandlesFetchEvents(bool* aValue) {
    102  MOZ_ASSERT(aValue);
    103  MOZ_ASSERT(NS_IsMainThread());
    104 
    105  if (mHandlesFetch == Unknown) {
    106    return NS_ERROR_FAILURE;
    107  }
    108 
    109  *aValue = HandlesFetch();
    110  return NS_OK;
    111 }
    112 
    113 NS_IMETHODIMP
    114 ServiceWorkerInfo::GetInstalledTime(PRTime* _retval) {
    115  MOZ_ASSERT(NS_IsMainThread());
    116  MOZ_ASSERT(_retval);
    117  *_retval = mInstalledTime;
    118  return NS_OK;
    119 }
    120 
    121 NS_IMETHODIMP
    122 ServiceWorkerInfo::GetActivatedTime(PRTime* _retval) {
    123  MOZ_ASSERT(NS_IsMainThread());
    124  MOZ_ASSERT(_retval);
    125  *_retval = mActivatedTime;
    126  return NS_OK;
    127 }
    128 
    129 NS_IMETHODIMP
    130 ServiceWorkerInfo::GetRedundantTime(PRTime* _retval) {
    131  MOZ_ASSERT(NS_IsMainThread());
    132  MOZ_ASSERT(_retval);
    133  *_retval = mRedundantTime;
    134  return NS_OK;
    135 }
    136 
    137 NS_IMETHODIMP
    138 ServiceWorkerInfo::GetLifetimeDeadline(double* aLifetimeDeadline) {
    139  MOZ_ASSERT(NS_IsMainThread());
    140  MOZ_ASSERT(aLifetimeDeadline);
    141  TimeStamp deadline = mServiceWorkerPrivate->GetLifetimeDeadline();
    142  if (deadline.IsNull()) {
    143    *aLifetimeDeadline = 0;
    144    return NS_OK;
    145  }
    146  *aLifetimeDeadline =
    147      (deadline - TimeStamp::ProcessCreation()).ToMilliseconds();
    148  return NS_OK;
    149 }
    150 
    151 NS_IMETHODIMP
    152 ServiceWorkerInfo::GetNavigationFaultCount(uint32_t* aNavigationFaultCount) {
    153  MOZ_ASSERT(NS_IsMainThread());
    154  MOZ_ASSERT(aNavigationFaultCount);
    155  *aNavigationFaultCount = mNavigationFaultCount;
    156  return NS_OK;
    157 }
    158 
    159 NS_IMETHODIMP
    160 ServiceWorkerInfo::GetTestingInjectCancellation(
    161    nsresult* aTestingInjectCancellation) {
    162  MOZ_ASSERT(NS_IsMainThread());
    163  MOZ_ASSERT(aTestingInjectCancellation);
    164  *aTestingInjectCancellation = mTestingInjectCancellation;
    165  return NS_OK;
    166 }
    167 
    168 NS_IMETHODIMP
    169 ServiceWorkerInfo::SetTestingInjectCancellation(
    170    nsresult aTestingInjectCancellation) {
    171  MOZ_ASSERT(NS_IsMainThread());
    172  mTestingInjectCancellation = aTestingInjectCancellation;
    173  return NS_OK;
    174 }
    175 
    176 NS_IMETHODIMP
    177 ServiceWorkerInfo::AttachDebugger() {
    178  return mServiceWorkerPrivate->AttachDebugger();
    179 }
    180 
    181 NS_IMETHODIMP
    182 ServiceWorkerInfo::DetachDebugger() {
    183  return mServiceWorkerPrivate->DetachDebugger();
    184 }
    185 
    186 NS_IMETHODIMP
    187 ServiceWorkerInfo::TerminateWorker(JSContext* aCx,
    188                                   mozilla::dom::Promise** aPromise) {
    189  nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
    190  if (NS_WARN_IF(!global)) {
    191    return NS_ERROR_FAILURE;
    192  }
    193 
    194  ErrorResult rv;
    195  RefPtr<Promise> outer = Promise::Create(global, rv);
    196  if (NS_WARN_IF(rv.Failed())) {
    197    return rv.StealNSResult();
    198  }
    199 
    200  mServiceWorkerPrivate->TerminateWorker(Some(outer));
    201  return NS_OK;
    202 }
    203 
    204 void ServiceWorkerInfo::UpdateState(ServiceWorkerState aState) {
    205  MOZ_ASSERT(NS_IsMainThread());
    206 #ifdef DEBUG
    207  // Any state can directly transition to redundant, but everything else is
    208  // ordered.
    209  if (aState != ServiceWorkerState::Redundant) {
    210    MOZ_ASSERT_IF(State() == ServiceWorkerState::Installing,
    211                  aState == ServiceWorkerState::Installed);
    212    MOZ_ASSERT_IF(State() == ServiceWorkerState::Installed,
    213                  aState == ServiceWorkerState::Activating);
    214    MOZ_ASSERT_IF(State() == ServiceWorkerState::Activating,
    215                  aState == ServiceWorkerState::Activated);
    216  }
    217  // Activated can only go to redundant.
    218  MOZ_ASSERT_IF(State() == ServiceWorkerState::Activated,
    219                aState == ServiceWorkerState::Redundant);
    220 #endif
    221  // Flush any pending functional events to the worker when it transitions to
    222  // the activated state.
    223  // TODO: Do we care that these events will race with the propagation of the
    224  //       state change?
    225  if (State() != aState) {
    226    mServiceWorkerPrivate->UpdateState(aState);
    227  }
    228  mDescriptor.SetState(aState);
    229  if (State() == ServiceWorkerState::Redundant) {
    230    serviceWorkerScriptCache::PurgeCache(mPrincipal, mCacheName);
    231    mServiceWorkerPrivate->NoteDeadServiceWorkerInfo();
    232  }
    233 }
    234 
    235 ServiceWorkerInfo::ServiceWorkerInfo(
    236    nsIPrincipal* aPrincipal, const nsACString& aScope, const WorkerType& aType,
    237    uint64_t aRegistrationId, uint64_t aRegistrationVersion,
    238    const nsACString& aScriptSpec, const nsAString& aCacheName,
    239    nsLoadFlags aImportsLoadFlags)
    240    : mPrincipal(aPrincipal),
    241      mDescriptor(GetNextID(), aRegistrationId, aRegistrationVersion,
    242                  aPrincipal, aScope, aType, aScriptSpec,
    243                  ServiceWorkerState::Parsed),
    244      mCacheName(aCacheName),
    245      mWorkerPrivateId(ComputeWorkerPrivateId()),
    246      mImportsLoadFlags(aImportsLoadFlags),
    247      mCreationTime(PR_Now()),
    248      mCreationTimeStamp(TimeStamp::Now()),
    249      mInstalledTime(0),
    250      mActivatedTime(0),
    251      mRedundantTime(0),
    252      mServiceWorkerPrivate(new ServiceWorkerPrivate(this)),
    253      mSkipWaitingFlag(false),
    254      mHandlesFetch(Unknown),
    255      mNavigationFaultCount(0),
    256      mTestingInjectCancellation(NS_OK) {
    257  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
    258  MOZ_ASSERT(mPrincipal);
    259  // cache origin attributes so we can use them off main thread
    260  mOriginAttributes = mPrincipal->OriginAttributesRef();
    261  MOZ_ASSERT(!mDescriptor.ScriptURL().IsEmpty());
    262  MOZ_ASSERT(!mCacheName.IsEmpty());
    263  MOZ_ASSERT(!mWorkerPrivateId.IsEmpty());
    264 
    265  // Scripts of a service worker should always be loaded bypass service workers.
    266  // Otherwise, we might not be able to update a service worker correctly, if
    267  // there is a service worker generating the script.
    268  MOZ_DIAGNOSTIC_ASSERT(mImportsLoadFlags &
    269                        nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
    270 }
    271 
    272 ServiceWorkerInfo::~ServiceWorkerInfo() {
    273  MOZ_ASSERT(mServiceWorkerPrivate);
    274  mServiceWorkerPrivate->NoteDeadServiceWorkerInfo();
    275 }
    276 
    277 static uint64_t gServiceWorkerInfoCurrentID = 0;
    278 
    279 uint64_t ServiceWorkerInfo::GetNextID() const {
    280  return ++gServiceWorkerInfoCurrentID;
    281 }
    282 
    283 void ServiceWorkerInfo::PostMessage(RefPtr<ServiceWorkerCloneData>&& aData,
    284                                    const PostMessageSource& aSource) {
    285  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
    286  if (NS_WARN_IF(!swm)) {
    287    return;
    288  }
    289 
    290  ServiceWorkerLifetimeExtension lifetime =
    291      ServiceWorkerLifetimeExtension(NoLifetimeExtension{});
    292 
    293  switch (aSource.type()) {
    294    case PostMessageSource::TClientInfoAndState:
    295      lifetime = swm->DetermineLifetimeForClient(
    296          ClientInfo(aSource.get_ClientInfoAndState().info()));
    297      break;
    298    case PostMessageSource::TIPCServiceWorkerDescriptor:
    299      lifetime = swm->DetermineLifetimeForServiceWorker(
    300          ServiceWorkerDescriptor(aSource.get_IPCServiceWorkerDescriptor()));
    301      break;
    302    default:
    303      MOZ_ASSERT_UNREACHABLE("Unexpected source type");
    304      return;
    305  }
    306 
    307  mServiceWorkerPrivate->SendMessageEvent(std::move(aData), lifetime, aSource);
    308 }
    309 
    310 Maybe<ClientInfo> ServiceWorkerInfo::GetClientInfo() {
    311  return mServiceWorkerPrivate->GetClientInfo();
    312 }
    313 
    314 TimeStamp ServiceWorkerInfo::LifetimeDeadline() {
    315  return mServiceWorkerPrivate->GetLifetimeDeadline();
    316 }
    317 
    318 void ServiceWorkerInfo::UpdateInstalledTime() {
    319  MOZ_ASSERT(State() == ServiceWorkerState::Installed);
    320  MOZ_ASSERT(mInstalledTime == 0);
    321 
    322  mInstalledTime =
    323      mCreationTime +
    324      static_cast<PRTime>(
    325          (TimeStamp::Now() - mCreationTimeStamp).ToMicroseconds());
    326 }
    327 
    328 void ServiceWorkerInfo::UpdateActivatedTime() {
    329  MOZ_ASSERT(State() == ServiceWorkerState::Activated);
    330  MOZ_ASSERT(mActivatedTime == 0);
    331 
    332  mActivatedTime =
    333      mCreationTime +
    334      static_cast<PRTime>(
    335          (TimeStamp::Now() - mCreationTimeStamp).ToMicroseconds());
    336 }
    337 
    338 void ServiceWorkerInfo::UpdateRedundantTime() {
    339  MOZ_ASSERT(State() == ServiceWorkerState::Redundant);
    340  MOZ_ASSERT(mRedundantTime == 0);
    341 
    342  mRedundantTime =
    343      mCreationTime +
    344      static_cast<PRTime>(
    345          (TimeStamp::Now() - mCreationTimeStamp).ToMicroseconds());
    346 }
    347 
    348 void ServiceWorkerInfo::SetRegistrationVersion(uint64_t aVersion) {
    349  mDescriptor.SetRegistrationVersion(aVersion);
    350 }
    351 
    352 }  // namespace mozilla::dom