tor-browser

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

ClientManager.cpp (13118B)


      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 "ClientManager.h"
      8 
      9 #include "ClientHandle.h"
     10 #include "ClientManagerChild.h"
     11 #include "ClientManagerOpChild.h"
     12 #include "ClientSource.h"
     13 #include "mozilla/ClearOnShutdown.h"  // PastShutdownPhase
     14 #include "mozilla/StaticPrefs_dom.h"
     15 #include "mozilla/dom/WorkerPrivate.h"
     16 #include "mozilla/ipc/BackgroundChild.h"
     17 #include "mozilla/ipc/PBackgroundChild.h"
     18 #include "prthread.h"
     19 
     20 namespace mozilla::dom {
     21 
     22 using mozilla::ipc::BackgroundChild;
     23 using mozilla::ipc::PBackgroundChild;
     24 using mozilla::ipc::PrincipalInfo;
     25 
     26 namespace {
     27 
     28 const uint32_t kBadThreadLocalIndex = -1;
     29 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     30 const uint32_t kThreadLocalMagic1 = 0x8d57eea6;
     31 const uint32_t kThreadLocalMagic2 = 0x59f375c9;
     32 #endif
     33 
     34 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     35 uint32_t sClientManagerThreadLocalMagic1 = kThreadLocalMagic1;
     36 #endif
     37 
     38 uint32_t sClientManagerThreadLocalIndex = kBadThreadLocalIndex;
     39 
     40 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     41 uint32_t sClientManagerThreadLocalMagic2 = kThreadLocalMagic2;
     42 uint32_t sClientManagerThreadLocalIndexDuplicate = kBadThreadLocalIndex;
     43 #endif
     44 
     45 }  // anonymous namespace
     46 
     47 ClientManager::ClientManager() {
     48  PBackgroundChild* parentActor =
     49      BackgroundChild::GetOrCreateForCurrentThread();
     50  if (NS_WARN_IF(!parentActor)) {
     51    Shutdown();
     52    return;
     53  }
     54 
     55  RefPtr<ClientManagerChild> actor = ClientManagerChild::Create();
     56  if (NS_WARN_IF(!actor)) {
     57    Shutdown();
     58    return;
     59  }
     60 
     61  PClientManagerChild* sentActor =
     62      parentActor->SendPClientManagerConstructor(actor);
     63  if (NS_WARN_IF(!sentActor)) {
     64    Shutdown();
     65    return;
     66  }
     67  MOZ_DIAGNOSTIC_ASSERT(sentActor == actor);
     68 
     69  ActivateThing(actor);
     70 }
     71 
     72 ClientManager::~ClientManager() {
     73  NS_ASSERT_OWNINGTHREAD(ClientManager);
     74 
     75  Shutdown();
     76 
     77  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1);
     78  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2);
     79  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
     80  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex ==
     81                        sClientManagerThreadLocalIndexDuplicate);
     82  MOZ_DIAGNOSTIC_ASSERT(this ==
     83                        PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
     84 
     85 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     86  PRStatus status =
     87 #endif
     88      PR_SetThreadPrivate(sClientManagerThreadLocalIndex, nullptr);
     89  MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
     90 }
     91 
     92 void ClientManager::Shutdown() {
     93  NS_ASSERT_OWNINGTHREAD(ClientManager);
     94 
     95  if (IsShutdown()) {
     96    return;
     97  }
     98 
     99  ShutdownThing();
    100 }
    101 
    102 UniquePtr<ClientSource> ClientManager::CreateSourceInternal(
    103    ClientType aType, nsISerialEventTarget* aEventTarget,
    104    const PrincipalInfo& aPrincipal) {
    105  NS_ASSERT_OWNINGTHREAD(ClientManager);
    106 
    107  nsID id;
    108  nsresult rv = nsID::GenerateUUIDInPlace(id);
    109  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    110  if (NS_WARN_IF(NS_FAILED(rv))) {
    111    // If we can't even get a UUID, at least make sure not to use a garbage
    112    // value.  Instead return a shutdown ClientSource with a zero'd id.
    113    // This should be exceptionally rare, if it happens at all.
    114    id.Clear();
    115    ClientSourceConstructorArgs args(id, Nothing(), aType, aPrincipal,
    116                                     TimeStamp::Now(), VoidCString(),
    117                                     FrameType::None);
    118    UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args));
    119    source->Shutdown();
    120    return source;
    121  }
    122 
    123  ClientSourceConstructorArgs args(id, Nothing(), aType, aPrincipal,
    124                                   TimeStamp::Now(), VoidCString(),
    125                                   FrameType::None);
    126  UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args));
    127 
    128  if (IsShutdown()) {
    129    source->Shutdown();
    130    return source;
    131  }
    132 
    133  source->Activate(GetActor());
    134 
    135  return source;
    136 }
    137 
    138 UniquePtr<ClientSource> ClientManager::CreateSourceInternal(
    139    const ClientInfo& aClientInfo, nsISerialEventTarget* aEventTarget) {
    140  NS_ASSERT_OWNINGTHREAD(ClientManager);
    141 
    142  ClientSourceConstructorArgs args(
    143      aClientInfo.Id(), aClientInfo.AgentClusterId(), aClientInfo.Type(),
    144      aClientInfo.PrincipalInfo(), aClientInfo.CreationTime(),
    145      aClientInfo.URL(), aClientInfo.FrameType());
    146  UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args));
    147 
    148  if (IsShutdown()) {
    149    source->Shutdown();
    150    return source;
    151  }
    152 
    153  source->Activate(GetActor());
    154 
    155  return source;
    156 }
    157 
    158 already_AddRefed<ClientHandle> ClientManager::CreateHandleInternal(
    159    const ClientInfo& aClientInfo, nsISerialEventTarget* aSerialEventTarget) {
    160  NS_ASSERT_OWNINGTHREAD(ClientManager);
    161  MOZ_DIAGNOSTIC_ASSERT(aSerialEventTarget);
    162 
    163  RefPtr<ClientHandle> handle =
    164      new ClientHandle(this, aSerialEventTarget, aClientInfo);
    165 
    166  if (IsShutdown()) {
    167    handle->Shutdown();
    168    return handle.forget();
    169  }
    170 
    171  handle->Activate(GetActor());
    172 
    173  return handle.forget();
    174 }
    175 
    176 RefPtr<ClientOpPromise> ClientManager::StartOp(
    177    const ClientOpConstructorArgs& aArgs,
    178    nsISerialEventTarget* aSerialEventTarget) {
    179  RefPtr<ClientOpPromise::Private> promise =
    180      new ClientOpPromise::Private(__func__);
    181 
    182  // Hold a ref to the client until the remote operation completes.  Otherwise
    183  // the ClientHandle might get de-refed and teardown the actor before we
    184  // get an answer.
    185  RefPtr<ClientManager> kungFuGrip = this;
    186 
    187  MaybeExecute(
    188      [&aArgs, promise, kungFuGrip](ClientManagerChild* aActor) {
    189        ClientManagerOpChild* actor =
    190            new ClientManagerOpChild(kungFuGrip, aArgs, promise);
    191        if (!aActor->SendPClientManagerOpConstructor(actor, aArgs)) {
    192          // Constructor failure will reject promise via ActorDestroy()
    193          return;
    194        }
    195      },
    196      [promise] {
    197        CopyableErrorResult rv;
    198        rv.ThrowInvalidStateError("Client has been destroyed");
    199        promise->Reject(rv, __func__);
    200      });
    201 
    202  return promise;
    203 }
    204 
    205 // static
    206 already_AddRefed<ClientManager> ClientManager::GetOrCreateForCurrentThread() {
    207  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1);
    208  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2);
    209  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
    210  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex ==
    211                        sClientManagerThreadLocalIndexDuplicate);
    212  RefPtr<ClientManager> cm = static_cast<ClientManager*>(
    213      PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
    214 
    215  if (!cm) {
    216    cm = new ClientManager();
    217 
    218 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    219    PRStatus status =
    220 #endif
    221        PR_SetThreadPrivate(sClientManagerThreadLocalIndex, cm.get());
    222    MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
    223  }
    224 
    225  MOZ_DIAGNOSTIC_ASSERT(cm);
    226 
    227  if (StaticPrefs::dom_workers_testing_enabled()) {
    228    // Check that the ClientManager instance associated to the current thread
    229    // has not been kept alive when it was expected to have been already
    230    // deallocated (e.g. due to a leak ClientManager's mShutdown can have ben
    231    // set to true from its RevokeActor method but never fully deallocated and
    232    // unset from the thread locals).
    233    MOZ_DIAGNOSTIC_ASSERT(!cm->IsShutdown());
    234  }
    235  return cm.forget();
    236 }
    237 
    238 WorkerPrivate* ClientManager::GetWorkerPrivate() const {
    239  NS_ASSERT_OWNINGTHREAD(ClientManager);
    240  MOZ_DIAGNOSTIC_ASSERT(GetActor());
    241  return GetActor()->GetWorkerPrivate();
    242 }
    243 
    244 // Used to share logic between ExpectFutureSource and ForgetFutureSource.
    245 /* static */ bool ClientManager::ExpectOrForgetFutureSource(
    246    const ClientInfo& aClientInfo,
    247    bool (PClientManagerChild::*aMethod)(const IPCClientInfo&)) {
    248  // Return earlier if called late in the XPCOM shutdown path,
    249  // ClientManager would be already shutdown at the point.
    250  if (NS_WARN_IF(PastShutdownPhase(ShutdownPhase::XPCOMShutdown))) {
    251    return false;
    252  }
    253 
    254  bool rv = true;
    255 
    256  RefPtr<ClientManager> mgr = ClientManager::GetOrCreateForCurrentThread();
    257  mgr->MaybeExecute(
    258      [&](ClientManagerChild* aActor) {
    259        if (!(aActor->*aMethod)(aClientInfo.ToIPC())) {
    260          rv = false;
    261        }
    262      },
    263      [&] { rv = false; });
    264 
    265  return rv;
    266 }
    267 
    268 /* static */ bool ClientManager::ExpectFutureSource(
    269    const ClientInfo& aClientInfo) {
    270  return ExpectOrForgetFutureSource(
    271      aClientInfo, &PClientManagerChild::SendExpectFutureClientSource);
    272 }
    273 
    274 /* static */ bool ClientManager::ForgetFutureSource(
    275    const ClientInfo& aClientInfo) {
    276  return ExpectOrForgetFutureSource(
    277      aClientInfo, &PClientManagerChild::SendForgetFutureClientSource);
    278 }
    279 
    280 // static
    281 void ClientManager::Startup() {
    282  MOZ_ASSERT(NS_IsMainThread());
    283 
    284  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1);
    285  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2);
    286  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == kBadThreadLocalIndex);
    287  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex ==
    288                        sClientManagerThreadLocalIndexDuplicate);
    289 
    290 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    291  PRStatus status =
    292 #endif
    293      PR_NewThreadPrivateIndex(&sClientManagerThreadLocalIndex, nullptr);
    294  MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
    295 
    296  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
    297 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    298  sClientManagerThreadLocalIndexDuplicate = sClientManagerThreadLocalIndex;
    299 #endif
    300 }
    301 
    302 // static
    303 UniquePtr<ClientSource> ClientManager::CreateSource(
    304    ClientType aType, nsISerialEventTarget* aEventTarget,
    305    nsIPrincipal* aPrincipal) {
    306  MOZ_ASSERT(NS_IsMainThread());
    307  MOZ_ASSERT(aPrincipal);
    308 
    309  PrincipalInfo principalInfo;
    310  nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
    311  if (NS_WARN_IF(NS_FAILED(rv))) {
    312    MOZ_CRASH("ClientManager::CreateSource() cannot serialize bad principal");
    313  }
    314 
    315  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
    316  return mgr->CreateSourceInternal(aType, aEventTarget, principalInfo);
    317 }
    318 
    319 // static
    320 UniquePtr<ClientSource> ClientManager::CreateSource(
    321    ClientType aType, nsISerialEventTarget* aEventTarget,
    322    const PrincipalInfo& aPrincipal) {
    323  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
    324  return mgr->CreateSourceInternal(aType, aEventTarget, aPrincipal);
    325 }
    326 
    327 // static
    328 UniquePtr<ClientSource> ClientManager::CreateSourceFromInfo(
    329    const ClientInfo& aClientInfo, nsISerialEventTarget* aEventTarget) {
    330  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
    331  return mgr->CreateSourceInternal(aClientInfo, aEventTarget);
    332 }
    333 
    334 Maybe<ClientInfo> ClientManager::CreateInfo(ClientType aType,
    335                                            nsIPrincipal* aPrincipal) {
    336  MOZ_ASSERT(NS_IsMainThread());
    337  MOZ_ASSERT(aPrincipal);
    338 
    339  PrincipalInfo principalInfo;
    340  nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
    341  if (NS_WARN_IF(NS_FAILED(rv))) {
    342    MOZ_CRASH("ClientManager::CreateSource() cannot serialize bad principal");
    343  }
    344 
    345  nsID id;
    346  rv = nsID::GenerateUUIDInPlace(id);
    347  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    348  if (NS_WARN_IF(NS_FAILED(rv))) {
    349    return Nothing();
    350  }
    351 
    352  return Some(ClientInfo(id, Nothing(), aType, principalInfo, TimeStamp::Now(),
    353                         ""_ns, FrameType::None));
    354 }
    355 
    356 // static
    357 already_AddRefed<ClientHandle> ClientManager::CreateHandle(
    358    const ClientInfo& aClientInfo, nsISerialEventTarget* aSerialEventTarget) {
    359  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
    360  return mgr->CreateHandleInternal(aClientInfo, aSerialEventTarget);
    361 }
    362 
    363 // static
    364 RefPtr<ClientOpPromise> ClientManager::MatchAll(
    365    const ClientMatchAllArgs& aArgs, nsISerialEventTarget* aSerialEventTarget) {
    366  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
    367  return mgr->StartOp(aArgs, aSerialEventTarget);
    368 }
    369 
    370 // static
    371 RefPtr<ClientOpPromise> ClientManager::Claim(
    372    const ClientClaimArgs& aArgs, nsISerialEventTarget* aSerialEventTarget) {
    373  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
    374  return mgr->StartOp(aArgs, aSerialEventTarget);
    375 }
    376 
    377 // static
    378 RefPtr<ClientOpPromise> ClientManager::GetInfoAndState(
    379    const ClientGetInfoAndStateArgs& aArgs,
    380    nsISerialEventTarget* aSerialEventTarget) {
    381  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
    382  return mgr->StartOp(aArgs, aSerialEventTarget);
    383 }
    384 
    385 // static
    386 RefPtr<ClientOpPromise> ClientManager::Navigate(
    387    const ClientNavigateArgs& aArgs, nsISerialEventTarget* aSerialEventTarget) {
    388  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
    389  return mgr->StartOp(aArgs, aSerialEventTarget);
    390 }
    391 
    392 // static
    393 RefPtr<ClientOpPromise> ClientManager::OpenWindow(
    394    const ClientOpenWindowArgs& aArgs,
    395    nsISerialEventTarget* aSerialEventTarget) {
    396  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
    397  return mgr->StartOp(aArgs, aSerialEventTarget);
    398 }
    399 
    400 }  // namespace mozilla::dom