tor-browser

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

ClientSourceParent.cpp (8167B)


      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 "ClientSourceParent.h"
      8 
      9 #include "ClientHandleParent.h"
     10 #include "ClientManagerService.h"
     11 #include "ClientSourceOpParent.h"
     12 #include "ClientValidation.h"
     13 #include "mozilla/SchedulerGroup.h"
     14 #include "mozilla/dom/ClientIPCTypes.h"
     15 #include "mozilla/dom/ContentParent.h"
     16 #include "mozilla/dom/PClientManagerParent.h"
     17 #include "mozilla/dom/ServiceWorkerManager.h"
     18 #include "mozilla/dom/ServiceWorkerUtils.h"
     19 #include "mozilla/ipc/BackgroundParent.h"
     20 
     21 namespace mozilla::dom {
     22 
     23 using mozilla::ipc::AssertIsOnBackgroundThread;
     24 using mozilla::ipc::BackgroundParent;
     25 using mozilla::ipc::IPCResult;
     26 using mozilla::ipc::PrincipalInfo;
     27 
     28 mozilla::ipc::IPCResult ClientSourceParent::RecvWorkerSyncPing() {
     29  AssertIsOnBackgroundThread();
     30  // Do nothing here.  This is purely a sync message allowing the child to
     31  // confirm that the actor has been created on the parent process.
     32  return IPC_OK();
     33 }
     34 
     35 IPCResult ClientSourceParent::RecvTeardown() {
     36  (void)Send__delete__(this);
     37  return IPC_OK();
     38 }
     39 
     40 IPCResult ClientSourceParent::RecvExecutionReady(
     41    const ClientSourceExecutionReadyArgs& aArgs) {
     42  // Now that we have the creation URL for the Client we can do some validation
     43  // to make sure the child actor is not giving us garbage.  Since we validate
     44  // on the child side as well we treat a failure here as fatal.
     45  if (!ClientIsValidCreationURL(mClientInfo.PrincipalInfo(), aArgs.url())) {
     46    return IPC_FAIL(this, "Invalid creation URL!");
     47  }
     48 
     49  mClientInfo.SetURL(aArgs.url());
     50  mClientInfo.SetFrameType(aArgs.frameType());
     51  mExecutionReady = true;
     52 
     53  for (ClientHandleParent* handle : mHandleList) {
     54    (void)handle->SendExecutionReady(mClientInfo.ToIPC());
     55  }
     56 
     57  mExecutionReadyPromise.ResolveIfExists(true, __func__);
     58 
     59  return IPC_OK();
     60 };
     61 
     62 IPCResult ClientSourceParent::RecvFreeze() {
     63 #ifdef FUZZING_SNAPSHOT
     64  if (mFrozen) {
     65    return IPC_FAIL(this, "Freezing when already frozen");
     66  }
     67 #endif
     68  MOZ_DIAGNOSTIC_ASSERT(!mFrozen);
     69  mFrozen = true;
     70 
     71  return IPC_OK();
     72 }
     73 
     74 IPCResult ClientSourceParent::RecvThaw() {
     75 #ifdef FUZZING_SNAPSHOT
     76  if (!mFrozen) {
     77    return IPC_FAIL(this, "Thawing when not already frozen");
     78  }
     79 #endif
     80  MOZ_DIAGNOSTIC_ASSERT(mFrozen);
     81  mFrozen = false;
     82  return IPC_OK();
     83 }
     84 
     85 IPCResult ClientSourceParent::RecvInheritController(
     86    const ClientControlledArgs& aArgs) {
     87  mController.reset();
     88  mController.emplace(aArgs.serviceWorker());
     89 
     90  // We must tell the parent-side SWM about this controller inheritance.
     91  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
     92      "ClientSourceParent::RecvInheritController",
     93      [clientInfo = mClientInfo, controller = mController.ref()]() {
     94        RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     95        NS_ENSURE_TRUE_VOID(swm);
     96 
     97        swm->NoteInheritedController(clientInfo, controller);
     98      });
     99 
    100  MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
    101 
    102  return IPC_OK();
    103 }
    104 
    105 IPCResult ClientSourceParent::RecvNoteDOMContentLoaded() {
    106  if (mController.isSome()) {
    107    nsCOMPtr<nsIRunnable> r =
    108        NS_NewRunnableFunction("ClientSourceParent::RecvNoteDOMContentLoaded",
    109                               [clientInfo = mClientInfo]() {
    110                                 RefPtr<ServiceWorkerManager> swm =
    111                                     ServiceWorkerManager::GetInstance();
    112                                 NS_ENSURE_TRUE_VOID(swm);
    113 
    114                                 swm->MaybeCheckNavigationUpdate(clientInfo);
    115                               });
    116 
    117    MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
    118  }
    119  return IPC_OK();
    120 }
    121 
    122 void ClientSourceParent::ActorDestroy(ActorDestroyReason aReason) {
    123  DebugOnly<bool> removed = mService->RemoveSource(this);
    124  MOZ_ASSERT(removed);
    125 
    126  for (ClientHandleParent* handle : mHandleList.Clone()) {
    127    // This should trigger DetachHandle() to be called removing
    128    // the entry from the mHandleList.
    129    (void)ClientHandleParent::Send__delete__(handle);
    130  }
    131  MOZ_DIAGNOSTIC_ASSERT(mHandleList.IsEmpty());
    132 }
    133 
    134 PClientSourceOpParent* ClientSourceParent::AllocPClientSourceOpParent(
    135    const ClientOpConstructorArgs& aArgs) {
    136  MOZ_ASSERT_UNREACHABLE(
    137      "ClientSourceOpParent should be explicitly constructed.");
    138  return nullptr;
    139 }
    140 
    141 bool ClientSourceParent::DeallocPClientSourceOpParent(
    142    PClientSourceOpParent* aActor) {
    143  delete aActor;
    144  return true;
    145 }
    146 
    147 ClientSourceParent::ClientSourceParent(
    148    const ClientSourceConstructorArgs& aArgs,
    149    const Maybe<ContentParentId>& aContentParentId)
    150    : mClientInfo(aArgs.id(), aArgs.agentClusterId(), aArgs.type(),
    151                  aArgs.principalInfo(), aArgs.creationTime(), aArgs.url(),
    152                  aArgs.frameType()),
    153      mContentParentId(aContentParentId),
    154      mService(ClientManagerService::GetOrCreateInstance()),
    155      mExecutionReady(false),
    156      mFrozen(false) {}
    157 
    158 ClientSourceParent::~ClientSourceParent() {
    159  MOZ_DIAGNOSTIC_ASSERT(mHandleList.IsEmpty());
    160 
    161  mExecutionReadyPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
    162 }
    163 
    164 IPCResult ClientSourceParent::Init() {
    165  // Ensure the principal is reasonable before adding ourself to the service.
    166  // Since we validate the principal on the child side as well, any failure
    167  // here is treated as fatal.
    168  if (NS_WARN_IF(!ClientIsValidPrincipalInfo(mClientInfo.PrincipalInfo()))) {
    169    mService->ForgetFutureSource(mClientInfo.ToIPC());
    170    return IPC_FAIL(Manager(), "Invalid PrincipalInfo!");
    171  }
    172 
    173  // Its possible for AddSource() to fail if there is already an entry for
    174  // our UUID.  This should not normally happen, but could if someone is
    175  // spoofing IPC messages.
    176  if (NS_WARN_IF(!mService->AddSource(this))) {
    177    return IPC_FAIL(Manager(), "Already registered!");
    178  }
    179 
    180  return IPC_OK();
    181 }
    182 
    183 const ClientInfo& ClientSourceParent::Info() const { return mClientInfo; }
    184 
    185 bool ClientSourceParent::IsFrozen() const { return mFrozen; }
    186 
    187 bool ClientSourceParent::ExecutionReady() const { return mExecutionReady; }
    188 
    189 RefPtr<GenericNonExclusivePromise> ClientSourceParent::ExecutionReadyPromise() {
    190  // Only call if ClientSourceParent::ExecutionReady() is false; otherwise,
    191  // the promise will never resolve
    192  MOZ_ASSERT(!mExecutionReady);
    193  return mExecutionReadyPromise.Ensure(__func__);
    194 }
    195 
    196 const Maybe<ServiceWorkerDescriptor>& ClientSourceParent::GetController()
    197    const {
    198  return mController;
    199 }
    200 
    201 void ClientSourceParent::ClearController() { mController.reset(); }
    202 
    203 void ClientSourceParent::AttachHandle(ClientHandleParent* aClientHandle) {
    204  MOZ_DIAGNOSTIC_ASSERT(aClientHandle);
    205  MOZ_ASSERT(!mHandleList.Contains(aClientHandle));
    206  mHandleList.AppendElement(aClientHandle);
    207 }
    208 
    209 void ClientSourceParent::DetachHandle(ClientHandleParent* aClientHandle) {
    210  MOZ_DIAGNOSTIC_ASSERT(aClientHandle);
    211  MOZ_ASSERT(mHandleList.Contains(aClientHandle));
    212  mHandleList.RemoveElement(aClientHandle);
    213 }
    214 
    215 RefPtr<ClientOpPromise> ClientSourceParent::StartOp(
    216    ClientOpConstructorArgs&& aArgs) {
    217  RefPtr<ClientOpPromise::Private> promise =
    218      new ClientOpPromise::Private(__func__);
    219 
    220  // If we are being controlled, remember that data before propagating
    221  // on to the ClientSource.  This must be set prior to triggering
    222  // the controllerchange event from the ClientSource since some tests
    223  // expect matchAll() to find the controlled client immediately after.
    224  // If the control operation fails, then we reset the controller value
    225  // to reflect the final state.
    226  if (aArgs.type() == ClientOpConstructorArgs::TClientControlledArgs) {
    227    mController.reset();
    228    mController.emplace(aArgs.get_ClientControlledArgs().serviceWorker());
    229  }
    230 
    231  // Constructor failure will reject the promise via ActorDestroy().
    232  ClientSourceOpParent* actor =
    233      new ClientSourceOpParent(std::move(aArgs), promise);
    234  (void)SendPClientSourceOpConstructor(actor, actor->Args());
    235 
    236  return promise;
    237 }
    238 
    239 }  // namespace mozilla::dom