tor-browser

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

JSActorService.cpp (12009B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 
      3 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      4 /* This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #include "mozilla/dom/JSActorService.h"
      9 
     10 #include "mozilla/ArrayAlgorithm.h"
     11 #include "mozilla/Logging.h"
     12 #include "mozilla/Services.h"
     13 #include "mozilla/StaticPtr.h"
     14 #include "mozilla/dom/BrowserChild.h"
     15 #include "mozilla/dom/BrowserParent.h"
     16 #include "mozilla/dom/ChromeUtilsBinding.h"
     17 #include "mozilla/dom/ContentChild.h"
     18 #include "mozilla/dom/ContentParent.h"
     19 #include "mozilla/dom/Event.h"
     20 #include "mozilla/dom/EventListenerBinding.h"
     21 #include "mozilla/dom/EventTarget.h"
     22 #include "mozilla/dom/EventTargetBinding.h"
     23 #include "mozilla/dom/InProcessChild.h"
     24 #include "mozilla/dom/InProcessParent.h"
     25 #include "mozilla/dom/JSActorManager.h"
     26 #include "mozilla/dom/JSProcessActorBinding.h"
     27 #include "mozilla/dom/JSProcessActorChild.h"
     28 #include "mozilla/dom/JSProcessActorProtocol.h"
     29 #include "mozilla/dom/JSWindowActorBinding.h"
     30 #include "mozilla/dom/JSWindowActorChild.h"
     31 #include "mozilla/dom/JSWindowActorProtocol.h"
     32 #include "mozilla/dom/MessageManagerBinding.h"
     33 #include "mozilla/dom/PContent.h"
     34 #include "mozilla/dom/WindowGlobalChild.h"
     35 #include "mozilla/dom/WindowGlobalParent.h"
     36 #include "nsIObserverService.h"
     37 
     38 namespace mozilla::dom {
     39 namespace {
     40 StaticRefPtr<JSActorService> gJSActorService;
     41 }
     42 
     43 JSActorService::JSActorService() { MOZ_ASSERT(NS_IsMainThread()); }
     44 
     45 JSActorService::~JSActorService() { MOZ_ASSERT(NS_IsMainThread()); }
     46 
     47 /* static */
     48 already_AddRefed<JSActorService> JSActorService::GetSingleton() {
     49  MOZ_ASSERT(NS_IsMainThread());
     50  if (!gJSActorService) {
     51    gJSActorService = new JSActorService();
     52    ClearOnShutdown(&gJSActorService);
     53  }
     54 
     55  RefPtr<JSActorService> service = gJSActorService.get();
     56  return service.forget();
     57 }
     58 
     59 void JSActorService::RegisterWindowActor(const nsACString& aName,
     60                                         const WindowActorOptions& aOptions,
     61                                         ErrorResult& aRv) {
     62  MOZ_ASSERT(NS_IsMainThread());
     63  MOZ_ASSERT(XRE_IsParentProcess());
     64 
     65  if (mProcessActorDescriptors.Contains(aName)) {
     66    aRv.ThrowNotSupportedError(
     67        nsPrintfCString("'%s' actor is already registered as a process actor.",
     68                        PromiseFlatCString(aName).get()));
     69    return;
     70  }
     71 
     72  const auto proto = mWindowActorDescriptors.WithEntryHandle(
     73      aName, [&](auto&& entry) -> RefPtr<JSWindowActorProtocol> {
     74        if (entry) {
     75          aRv.ThrowNotSupportedError(
     76              nsPrintfCString("'%s' actor is already registered.",
     77                              PromiseFlatCString(aName).get()));
     78          return nullptr;
     79        }
     80 
     81        // Insert a new entry for the protocol.
     82        RefPtr<JSWindowActorProtocol> protocol =
     83            JSWindowActorProtocol::FromWebIDLOptions(aName, aOptions, aRv);
     84        if (NS_WARN_IF(aRv.Failed())) {
     85          return nullptr;
     86        }
     87 
     88        entry.Insert(protocol);
     89 
     90        return protocol;
     91      });
     92 
     93  if (!proto) {
     94    MOZ_ASSERT(aRv.Failed());
     95    return;
     96  }
     97 
     98  // Send information about the newly added entry to every existing content
     99  // process.
    100  AutoTArray<JSWindowActorInfo, 1> windowInfos{proto->ToIPC()};
    101  nsTArray<JSProcessActorInfo> contentInfos{};
    102  for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
    103    (void)cp->SendInitJSActorInfos(contentInfos, windowInfos);
    104  }
    105 
    106  // Register event listeners for any existing chrome targets.
    107  for (EventTarget* target : mChromeEventTargets) {
    108    proto->RegisterListenersFor(target);
    109  }
    110 
    111  // Add observers to the protocol.
    112  proto->AddObservers();
    113 }
    114 
    115 void JSActorService::UnregisterWindowActor(const nsACString& aName) {
    116  MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
    117  CrashReporter::AutoRecordAnnotation autoActorName(
    118      CrashReporter::Annotation::JSActorName, aName);
    119  CrashReporter::AutoRecordAnnotation autoMessageName(
    120      CrashReporter::Annotation::JSActorMessage, "<Unregister>"_ns);
    121 
    122  nsAutoCString name(aName);
    123  RefPtr<JSWindowActorProtocol> proto;
    124  if (mWindowActorDescriptors.Remove(name, getter_AddRefs(proto))) {
    125    // Remove listeners for this actor from each of our chrome targets.
    126    for (EventTarget* target : mChromeEventTargets) {
    127      proto->UnregisterListenersFor(target);
    128    }
    129 
    130    // Remove observers for this actor from observer serivce.
    131    proto->RemoveObservers();
    132 
    133    // Tell every content process to also unregister, and accumulate the set of
    134    // potential managers, to have the actor disabled.
    135    nsTArray<RefPtr<JSActorManager>> managers;
    136    if (XRE_IsParentProcess()) {
    137      for (auto* cp : ContentParent::AllProcesses(ContentParent::eAll)) {
    138        if (cp->CanSend()) {
    139          (void)cp->SendUnregisterJSWindowActor(name);
    140        }
    141        for (const auto& bp : cp->ManagedPBrowserParent()) {
    142          for (const auto& wgp : bp->ManagedPWindowGlobalParent()) {
    143            managers.AppendElement(static_cast<WindowGlobalParent*>(wgp));
    144          }
    145        }
    146      }
    147 
    148      for (const auto& wgp :
    149           InProcessParent::Singleton()->ManagedPWindowGlobalParent()) {
    150        managers.AppendElement(static_cast<WindowGlobalParent*>(wgp));
    151      }
    152      for (const auto& wgc :
    153           InProcessChild::Singleton()->ManagedPWindowGlobalChild()) {
    154        managers.AppendElement(static_cast<WindowGlobalChild*>(wgc));
    155      }
    156    } else {
    157      for (const auto& bc :
    158           ContentChild::GetSingleton()->ManagedPBrowserChild()) {
    159        for (const auto& wgc : bc->ManagedPWindowGlobalChild()) {
    160          managers.AppendElement(static_cast<WindowGlobalChild*>(wgc));
    161        }
    162      }
    163    }
    164 
    165    for (auto& mgr : managers) {
    166      mgr->JSActorUnregister(name);
    167    }
    168  }
    169 }
    170 
    171 void JSActorService::LoadJSActorInfos(nsTArray<JSProcessActorInfo>& aProcess,
    172                                      nsTArray<JSWindowActorInfo>& aWindow) {
    173  MOZ_ASSERT(NS_IsMainThread());
    174  MOZ_ASSERT(XRE_IsContentProcess());
    175 
    176  for (auto& info : aProcess) {
    177    // Create our JSProcessActorProtocol, register it in
    178    // mProcessActorDescriptors.
    179    auto name = info.name();
    180    RefPtr<JSProcessActorProtocol> proto =
    181        JSProcessActorProtocol::FromIPC(std::move(info));
    182    mProcessActorDescriptors.InsertOrUpdate(std::move(name), RefPtr{proto});
    183 
    184    // Add observers for each actor.
    185    proto->AddObservers();
    186  }
    187 
    188  for (auto& info : aWindow) {
    189    auto name = info.name();
    190    RefPtr<JSWindowActorProtocol> proto =
    191        JSWindowActorProtocol::FromIPC(std::move(info));
    192    mWindowActorDescriptors.InsertOrUpdate(std::move(name), RefPtr{proto});
    193 
    194    // Register listeners for each chrome target.
    195    for (EventTarget* target : mChromeEventTargets) {
    196      proto->RegisterListenersFor(target);
    197    }
    198 
    199    // Add observers for each actor.
    200    proto->AddObservers();
    201  }
    202 }
    203 
    204 void JSActorService::GetJSWindowActorInfos(
    205    nsTArray<JSWindowActorInfo>& aInfos) {
    206  MOZ_ASSERT(NS_IsMainThread());
    207  MOZ_ASSERT(XRE_IsParentProcess());
    208 
    209  for (const auto& data : mWindowActorDescriptors.Values()) {
    210    aInfos.AppendElement(data->ToIPC());
    211  }
    212 }
    213 
    214 void JSActorService::RegisterChromeEventTarget(EventTarget* aTarget) {
    215  MOZ_ASSERT(!mChromeEventTargets.Contains(aTarget));
    216  mChromeEventTargets.AppendElement(aTarget);
    217 
    218  // Register event listeners on the newly added Window Root.
    219  for (const auto& data : mWindowActorDescriptors.Values()) {
    220    data->RegisterListenersFor(aTarget);
    221  }
    222 
    223  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
    224  obs->NotifyObservers(aTarget, "chrome-event-target-created", nullptr);
    225 }
    226 
    227 /* static */
    228 void JSActorService::UnregisterChromeEventTarget(EventTarget* aTarget) {
    229  if (gJSActorService) {
    230    // NOTE: No need to unregister listeners here, as the target is going away.
    231    gJSActorService->mChromeEventTargets.RemoveElement(aTarget);
    232  }
    233 }
    234 
    235 void JSActorService::RegisterProcessActor(const nsACString& aName,
    236                                          const ProcessActorOptions& aOptions,
    237                                          ErrorResult& aRv) {
    238  MOZ_ASSERT(NS_IsMainThread());
    239  MOZ_ASSERT(XRE_IsParentProcess());
    240 
    241  if (mWindowActorDescriptors.Contains(aName)) {
    242    aRv.ThrowNotSupportedError(
    243        nsPrintfCString("'%s' actor is already registered as a window actor.",
    244                        PromiseFlatCString(aName).get()));
    245    return;
    246  }
    247 
    248  const auto proto = mProcessActorDescriptors.WithEntryHandle(
    249      aName, [&](auto&& entry) -> RefPtr<JSProcessActorProtocol> {
    250        if (entry) {
    251          aRv.ThrowNotSupportedError(
    252              nsPrintfCString("'%s' actor is already registered.",
    253                              PromiseFlatCString(aName).get()));
    254          return nullptr;
    255        }
    256 
    257        // Insert a new entry for the protocol.
    258        RefPtr<JSProcessActorProtocol> protocol =
    259            JSProcessActorProtocol::FromWebIDLOptions(aName, aOptions, aRv);
    260        if (NS_WARN_IF(aRv.Failed())) {
    261          return nullptr;
    262        }
    263 
    264        entry.Insert(protocol);
    265 
    266        return protocol;
    267      });
    268 
    269  if (!proto) {
    270    MOZ_ASSERT(aRv.Failed());
    271    return;
    272  }
    273 
    274  // Send information about the newly added entry to every existing content
    275  // process.
    276  AutoTArray<JSProcessActorInfo, 1> contentInfos{proto->ToIPC()};
    277  nsTArray<JSWindowActorInfo> windowInfos{};
    278  for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
    279    (void)cp->SendInitJSActorInfos(contentInfos, windowInfos);
    280  }
    281 
    282  // Add observers to the protocol.
    283  proto->AddObservers();
    284 }
    285 
    286 void JSActorService::UnregisterProcessActor(const nsACString& aName) {
    287  MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
    288  CrashReporter::AutoRecordAnnotation autoActorName(
    289      CrashReporter::Annotation::JSActorName, aName);
    290  CrashReporter::AutoRecordAnnotation autoMessageName(
    291      CrashReporter::Annotation::JSActorMessage, "<Unregister>"_ns);
    292 
    293  nsAutoCString name(aName);
    294  RefPtr<JSProcessActorProtocol> proto;
    295  if (mProcessActorDescriptors.Remove(name, getter_AddRefs(proto))) {
    296    // Remove observers for this actor from observer serivce.
    297    proto->RemoveObservers();
    298 
    299    // Tell every content process to also unregister, and accumulate the set of
    300    // potential managers, to have the actor disabled.
    301    nsTArray<RefPtr<JSActorManager>> managers;
    302    if (XRE_IsParentProcess()) {
    303      for (auto* cp : ContentParent::AllProcesses(ContentParent::eAll)) {
    304        if (cp->CanSend()) {
    305          (void)cp->SendUnregisterJSProcessActor(name);
    306        }
    307        managers.AppendElement(cp);
    308      }
    309      managers.AppendElement(InProcessChild::Singleton());
    310      managers.AppendElement(InProcessParent::Singleton());
    311    } else {
    312      managers.AppendElement(ContentChild::GetSingleton());
    313    }
    314 
    315    for (auto& mgr : managers) {
    316      mgr->JSActorUnregister(name);
    317    }
    318  }
    319 }
    320 
    321 void JSActorService::GetJSProcessActorInfos(
    322    nsTArray<JSProcessActorInfo>& aInfos) {
    323  MOZ_ASSERT(NS_IsMainThread());
    324  MOZ_ASSERT(XRE_IsParentProcess());
    325 
    326  for (const auto& data : mProcessActorDescriptors.Values()) {
    327    aInfos.AppendElement(data->ToIPC());
    328  }
    329 }
    330 
    331 already_AddRefed<JSProcessActorProtocol>
    332 JSActorService::GetJSProcessActorProtocol(const nsACString& aName) {
    333  return mProcessActorDescriptors.Get(aName);
    334 }
    335 
    336 already_AddRefed<JSWindowActorProtocol>
    337 JSActorService::GetJSWindowActorProtocol(const nsACString& aName) {
    338  return mWindowActorDescriptors.Get(aName);
    339 }
    340 
    341 bool JSActorProtocol::RemoteTypePrefixMatches(const nsACString& aRemoteType) {
    342  if (mRemoteTypes.IsEmpty()) {
    343    return true;
    344  }
    345 
    346  nsDependentCSubstring remoteTypePrefix(RemoteTypePrefix(aRemoteType));
    347  for (auto& remoteType : mRemoteTypes) {
    348    // TODO: Maybe this should use glob-style matching instead. See bug 2006165.
    349    if (StringBeginsWith(remoteTypePrefix, remoteType)) {
    350      return true;
    351    }
    352  }
    353  return false;
    354 }
    355 
    356 }  // namespace mozilla::dom