tor-browser

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

SharedWorkerService.cpp (10282B)


      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 "SharedWorkerService.h"
      8 
      9 #include "mozilla/BasePrincipal.h"
     10 #include "mozilla/ClearOnShutdown.h"
     11 #include "mozilla/SchedulerGroup.h"
     12 #include "mozilla/StaticMutex.h"
     13 #include "mozilla/dom/MessagePort.h"
     14 #include "mozilla/dom/RemoteWorkerManager.h"  // RemoteWorkerManager::GetRemoteType
     15 #include "mozilla/dom/RemoteWorkerTypes.h"
     16 #include "mozilla/dom/SharedWorkerManager.h"
     17 #include "mozilla/ipc/BackgroundParent.h"
     18 #include "mozilla/ipc/URIUtils.h"
     19 #include "nsIPrincipal.h"
     20 #include "nsProxyRelease.h"
     21 
     22 namespace mozilla {
     23 
     24 using namespace ipc;
     25 
     26 namespace dom {
     27 
     28 namespace {
     29 
     30 StaticMutex sSharedWorkerMutex;
     31 
     32 StaticRefPtr<SharedWorkerService> sSharedWorkerService;
     33 
     34 class GetOrCreateWorkerManagerRunnable final : public Runnable {
     35 public:
     36  GetOrCreateWorkerManagerRunnable(SharedWorkerService* aService,
     37                                   SharedWorkerParent* aActor,
     38                                   const RemoteWorkerData& aData,
     39                                   uint64_t aWindowID,
     40                                   const MessagePortIdentifier& aPortIdentifier)
     41      : Runnable("GetOrCreateWorkerManagerRunnable"),
     42        mBackgroundEventTarget(GetCurrentSerialEventTarget()),
     43        mService(aService),
     44        mActor(aActor),
     45        mData(aData),
     46        mWindowID(aWindowID),
     47        mPortIdentifier(aPortIdentifier) {}
     48 
     49  NS_IMETHOD
     50  Run() {
     51    mService->GetOrCreateWorkerManagerOnMainThread(
     52        mBackgroundEventTarget, mActor, mData, mWindowID, mPortIdentifier);
     53 
     54    return NS_OK;
     55  }
     56 
     57 private:
     58  nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
     59  RefPtr<SharedWorkerService> mService;
     60  RefPtr<SharedWorkerParent> mActor;
     61  RemoteWorkerData mData;
     62  uint64_t mWindowID;
     63  UniqueMessagePortId mPortIdentifier;
     64 };
     65 
     66 class WorkerManagerCreatedRunnable final : public Runnable {
     67 public:
     68  WorkerManagerCreatedRunnable(
     69      already_AddRefed<SharedWorkerManagerWrapper> aManagerWrapper,
     70      SharedWorkerParent* aActor, const RemoteWorkerData& aData,
     71      uint64_t aWindowID, UniqueMessagePortId& aPortIdentifier)
     72      : Runnable("WorkerManagerCreatedRunnable"),
     73        mManagerWrapper(aManagerWrapper),
     74        mActor(aActor),
     75        mData(aData),
     76        mWindowID(aWindowID),
     77        mPortIdentifier(std::move(aPortIdentifier)) {}
     78 
     79  NS_IMETHOD
     80  Run() {
     81    AssertIsOnBackgroundThread();
     82 
     83    if (NS_WARN_IF(
     84            !mActor->CanSend() ||
     85            !mManagerWrapper->Manager()->MaybeCreateRemoteWorker(
     86                mData, mWindowID, mPortIdentifier, mActor->OtherPid()))) {
     87      // If we cannot send, the error won't arrive, but we may log something.
     88      mActor->ErrorPropagation(NS_ERROR_FAILURE);
     89      return NS_OK;
     90    }
     91 
     92    mManagerWrapper->Manager()->AddActor(mActor);
     93    mActor->ManagerCreated(mManagerWrapper.forget());
     94    return NS_OK;
     95  }
     96 
     97 private:
     98  RefPtr<SharedWorkerManagerWrapper> mManagerWrapper;
     99  RefPtr<SharedWorkerParent> mActor;
    100  RemoteWorkerData mData;
    101  uint64_t mWindowID;
    102  UniqueMessagePortId mPortIdentifier;
    103 };
    104 
    105 class ErrorPropagationRunnable final : public Runnable {
    106 public:
    107  ErrorPropagationRunnable(SharedWorkerParent* aActor, nsresult aError)
    108      : Runnable("ErrorPropagationRunnable"), mActor(aActor), mError(aError) {}
    109 
    110  NS_IMETHOD
    111  Run() {
    112    AssertIsOnBackgroundThread();
    113    mActor->ErrorPropagation(mError);
    114    return NS_OK;
    115  }
    116 
    117 private:
    118  RefPtr<SharedWorkerParent> mActor;
    119  nsresult mError;
    120 };
    121 
    122 }  // namespace
    123 
    124 /* static */
    125 already_AddRefed<SharedWorkerService> SharedWorkerService::GetOrCreate() {
    126  AssertIsOnBackgroundThread();
    127 
    128  StaticMutexAutoLock lock(sSharedWorkerMutex);
    129 
    130  if (!sSharedWorkerService) {
    131    sSharedWorkerService = new SharedWorkerService();
    132    // ClearOnShutdown can only be called on main thread
    133    nsresult rv = SchedulerGroup::Dispatch(NS_NewRunnableFunction(
    134        "RegisterSharedWorkerServiceClearOnShutdown", []() {
    135          StaticMutexAutoLock lock(sSharedWorkerMutex);
    136          MOZ_ASSERT(sSharedWorkerService);
    137          ClearOnShutdown(&sSharedWorkerService);
    138        }));
    139    (void)NS_WARN_IF(NS_FAILED(rv));
    140  }
    141 
    142  RefPtr<SharedWorkerService> instance = sSharedWorkerService;
    143  return instance.forget();
    144 }
    145 
    146 /* static */
    147 SharedWorkerService* SharedWorkerService::Get() {
    148  StaticMutexAutoLock lock(sSharedWorkerMutex);
    149 
    150  MOZ_ASSERT(sSharedWorkerService);
    151  return sSharedWorkerService;
    152 }
    153 
    154 void SharedWorkerService::GetOrCreateWorkerManager(
    155    SharedWorkerParent* aActor, const RemoteWorkerData& aData,
    156    uint64_t aWindowID, const MessagePortIdentifier& aPortIdentifier) {
    157  AssertIsOnBackgroundThread();
    158 
    159  // The real check happens on main-thread.
    160  RefPtr<GetOrCreateWorkerManagerRunnable> r =
    161      new GetOrCreateWorkerManagerRunnable(this, aActor, aData, aWindowID,
    162                                           aPortIdentifier);
    163 
    164  nsresult rv = SchedulerGroup::Dispatch(r.forget());
    165  (void)NS_WARN_IF(NS_FAILED(rv));
    166 }
    167 
    168 void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
    169    nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
    170    const RemoteWorkerData& aData, uint64_t aWindowID,
    171    UniqueMessagePortId& aPortIdentifier) {
    172  MOZ_ASSERT(NS_IsMainThread());
    173  MOZ_ASSERT(aBackgroundEventTarget);
    174  MOZ_ASSERT(aActor);
    175 
    176  RemoteWorkerData copyData = aData;
    177  auto principalOrErr = PrincipalInfoToPrincipal(copyData.principalInfo());
    178  if (NS_WARN_IF(principalOrErr.isErr())) {
    179    ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
    180                                 principalOrErr.unwrapErr());
    181    return;
    182  }
    183 
    184  nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
    185  auto remoteType = RemoteWorkerManager::GetRemoteType(
    186      principal, WorkerKind::WorkerKindShared);
    187  if (NS_WARN_IF(remoteType.isErr())) {
    188    ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
    189                                 remoteType.unwrapErr());
    190    return;
    191  }
    192 
    193  if (!remoteType.unwrap().Equals(copyData.remoteType())) {
    194    copyData.remoteType() = remoteType.unwrap();
    195  }
    196 
    197  auto partitionedPrincipalOrErr =
    198      PrincipalInfoToPrincipal(copyData.partitionedPrincipalInfo());
    199  if (NS_WARN_IF(partitionedPrincipalOrErr.isErr())) {
    200    ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
    201                                 partitionedPrincipalOrErr.unwrapErr());
    202    return;
    203  }
    204 
    205  auto loadingPrincipalOrErr =
    206      PrincipalInfoToPrincipal(copyData.loadingPrincipalInfo());
    207  if (NS_WARN_IF(loadingPrincipalOrErr.isErr())) {
    208    ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
    209                                 loadingPrincipalOrErr.unwrapErr());
    210    return;
    211  }
    212 
    213  RefPtr<SharedWorkerManagerHolder> managerHolder;
    214 
    215  nsCOMPtr<nsIPrincipal> loadingPrincipal = loadingPrincipalOrErr.unwrap();
    216  nsCOMPtr<nsIPrincipal> partitionedPrincipal =
    217      partitionedPrincipalOrErr.unwrap();
    218 
    219  nsCOMPtr<nsIPrincipal> effectiveStoragePrincipal = partitionedPrincipal;
    220  if (copyData.useRegularPrincipal()) {
    221    effectiveStoragePrincipal = loadingPrincipal;
    222  }
    223 
    224  // Let's see if there is already a SharedWorker to share.
    225  nsCOMPtr<nsIURI> resolvedScriptURL =
    226      DeserializeURI(copyData.resolvedScriptURL());
    227  for (SharedWorkerManager* workerManager : mWorkerManagers) {
    228    bool matchNameButNotOptions = false;
    229 
    230    managerHolder = workerManager->MatchOnMainThread(
    231        this, copyData, resolvedScriptURL, loadingPrincipal,
    232        BasePrincipal::Cast(effectiveStoragePrincipal)->OriginAttributesRef(),
    233        &matchNameButNotOptions);
    234    if (managerHolder) {
    235      break;
    236    }
    237 
    238    if (matchNameButNotOptions) {
    239      MismatchOptionsErrorPropagationOnMainThread(aBackgroundEventTarget,
    240                                                  aActor);
    241      return;
    242    }
    243  }
    244 
    245  // Let's create a new one.
    246  if (!managerHolder) {
    247    managerHolder = SharedWorkerManager::Create(
    248        this, aBackgroundEventTarget, copyData, loadingPrincipal,
    249        BasePrincipal::Cast(effectiveStoragePrincipal)->OriginAttributesRef());
    250 
    251    mWorkerManagers.AppendElement(managerHolder->Manager());
    252  } else {
    253    // We are attaching the actor to an existing one.
    254    if (managerHolder->Manager()->IsSecureContext() !=
    255        copyData.isSecureContext()) {
    256      ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
    257                                   NS_ERROR_DOM_SECURITY_ERR);
    258      return;
    259    }
    260  }
    261 
    262  RefPtr<SharedWorkerManagerWrapper> wrapper =
    263      new SharedWorkerManagerWrapper(managerHolder.forget());
    264 
    265  RefPtr<WorkerManagerCreatedRunnable> r = new WorkerManagerCreatedRunnable(
    266      wrapper.forget(), aActor, copyData, aWindowID, aPortIdentifier);
    267  aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
    268 }
    269 
    270 void SharedWorkerService::ErrorPropagationOnMainThread(
    271    nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
    272    nsresult aError) {
    273  MOZ_ASSERT(NS_IsMainThread());
    274  MOZ_ASSERT(aBackgroundEventTarget);
    275  MOZ_ASSERT(aActor);
    276  MOZ_ASSERT(NS_FAILED(aError));
    277 
    278  RefPtr<ErrorPropagationRunnable> r =
    279      new ErrorPropagationRunnable(aActor, aError);
    280  aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
    281 }
    282 
    283 void SharedWorkerService::MismatchOptionsErrorPropagationOnMainThread(
    284    nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor) {
    285  MOZ_ASSERT(NS_IsMainThread());
    286  MOZ_ASSERT(aBackgroundEventTarget);
    287  MOZ_ASSERT(aActor);
    288 
    289  aBackgroundEventTarget->Dispatch(
    290      NS_NewRunnableFunction(__func__,
    291                             [aActor = RefPtr(aActor)] {
    292                               AssertIsOnBackgroundThread();
    293                               aActor->MismatchOptionsErrorPropagation();
    294                             }),
    295      NS_DISPATCH_NORMAL);
    296 }
    297 
    298 void SharedWorkerService::RemoveWorkerManagerOnMainThread(
    299    SharedWorkerManager* aManager) {
    300  MOZ_ASSERT(NS_IsMainThread());
    301  MOZ_ASSERT(aManager);
    302  MOZ_ASSERT(mWorkerManagers.Contains(aManager));
    303 
    304  mWorkerManagers.RemoveElement(aManager);
    305 }
    306 
    307 }  // namespace dom
    308 }  // namespace mozilla