tor-browser

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

StreamList.cpp (6256B)


      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 "mozilla/dom/cache/StreamList.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "mozilla/dom/cache/CacheStreamControlParent.h"
     12 #include "mozilla/dom/cache/Context.h"
     13 #include "mozilla/dom/cache/Manager.h"
     14 #include "nsIInputStream.h"
     15 
     16 namespace mozilla::dom::cache {
     17 
     18 namespace {
     19 
     20 auto MatchById(const nsID& aId) {
     21  return [aId](const auto& entry) { return entry.mId == aId; };
     22 }
     23 
     24 }  // namespace
     25 
     26 StreamList::StreamList(SafeRefPtr<Manager> aManager,
     27                       SafeRefPtr<Context> aContext)
     28    : mManager(std::move(aManager)),
     29      mContext(std::move(aContext)),
     30      mCacheId(INVALID_CACHE_ID),
     31      mStreamControl(nullptr),
     32      mActivated(false) {
     33  MOZ_DIAGNOSTIC_ASSERT(mManager);
     34  mContext->AddActivity(*this);
     35 }
     36 
     37 Manager& StreamList::GetManager() const {
     38  MOZ_DIAGNOSTIC_ASSERT(mManager);
     39  return *mManager;
     40 }
     41 
     42 bool StreamList::ShouldOpenStreamFor(const nsID& aId) const {
     43  NS_ASSERT_OWNINGTHREAD(StreamList);
     44 
     45  return std::any_of(mList.cbegin(), mList.cend(), MatchById(aId));
     46 }
     47 
     48 void StreamList::SetStreamControl(CacheStreamControlParent* aStreamControl) {
     49  NS_ASSERT_OWNINGTHREAD(StreamList);
     50  MOZ_DIAGNOSTIC_ASSERT(aStreamControl);
     51 
     52  // For cases where multiple streams are serialized for a single list
     53  // then the control will get passed multiple times.  This is ok, but
     54  // it should be the same control each time.
     55  if (mStreamControl) {
     56    MOZ_DIAGNOSTIC_ASSERT(aStreamControl == mStreamControl);
     57    return;
     58  }
     59 
     60  mStreamControl = aStreamControl;
     61  mStreamControl->SetStreamList(SafeRefPtrFromThis());
     62 }
     63 
     64 void StreamList::RemoveStreamControl(CacheStreamControlParent* aStreamControl) {
     65  NS_ASSERT_OWNINGTHREAD(StreamList);
     66  MOZ_DIAGNOSTIC_ASSERT(mStreamControl);
     67  MOZ_DIAGNOSTIC_ASSERT(mStreamControl == aStreamControl);
     68  mStreamControl = nullptr;
     69 }
     70 
     71 void StreamList::Activate(CacheId aCacheId) {
     72  NS_ASSERT_OWNINGTHREAD(StreamList);
     73  MOZ_DIAGNOSTIC_ASSERT(!mActivated);
     74  MOZ_DIAGNOSTIC_ASSERT(mCacheId == INVALID_CACHE_ID);
     75  mActivated = true;
     76  mCacheId = aCacheId;
     77  mManager->AddRefCacheId(mCacheId);
     78  mManager->AddStreamList(*this);
     79 
     80  for (uint32_t i = 0; i < mList.Length(); ++i) {
     81    mManager->AddRefBodyId(mList[i].mId);
     82  }
     83 }
     84 
     85 void StreamList::Add(const nsID& aId, nsCOMPtr<nsIInputStream>&& aStream) {
     86  // All streams should be added on IO thread before we set the stream
     87  // control on the owning IPC thread.
     88  MOZ_DIAGNOSTIC_ASSERT(!mStreamControl);
     89 
     90  // Removal of the stream will be triggered when the stream is closed,
     91  // which happens only once, so let's ensure nobody adds us twice.
     92  MOZ_ASSERT_DEBUG_OR_FUZZING(
     93      std::find_if(mList.begin(), mList.end(), MatchById(aId)) == mList.end());
     94 
     95  mList.EmplaceBack(aId, std::move(aStream));
     96 }
     97 
     98 already_AddRefed<nsIInputStream> StreamList::Extract(const nsID& aId) {
     99  NS_ASSERT_OWNINGTHREAD(StreamList);
    100 
    101  const auto it = std::find_if(mList.begin(), mList.end(), MatchById(aId));
    102 
    103  // Note that if the stream has not been opened with OpenMode::Eager we will
    104  // find it nullptr here and it will have to be opened by the consumer.
    105 
    106  return it != mList.end() ? it->mStream.forget() : nullptr;
    107 }
    108 
    109 void StreamList::NoteClosed(const nsID& aId) {
    110  NS_ASSERT_OWNINGTHREAD(StreamList);
    111 
    112  const auto it = std::find_if(mList.begin(), mList.end(), MatchById(aId));
    113  if (it != mList.end()) {
    114    MOZ_ASSERT(!it->mStream, "We expect to find mStream already extracted.");
    115    mList.RemoveElementAt(it);
    116    mManager->ReleaseBodyId(aId);
    117  }
    118 
    119  if (mList.IsEmpty() && mStreamControl) {
    120    mStreamControl->Shutdown();
    121  }
    122 }
    123 
    124 void StreamList::NoteClosedAll() {
    125  NS_ASSERT_OWNINGTHREAD(StreamList);
    126  for (uint32_t i = 0; i < mList.Length(); ++i) {
    127    mManager->ReleaseBodyId(mList[i].mId);
    128  }
    129  mList.Clear();
    130 
    131  if (mStreamControl) {
    132    mStreamControl->Shutdown();
    133  }
    134 }
    135 
    136 void StreamList::CloseAll() {
    137  NS_ASSERT_OWNINGTHREAD(StreamList);
    138 
    139  if (mStreamControl && mStreamControl->CanSend()) {
    140    // CloseAll will kick off everything needed for shutdown.
    141    // mStreamControl may go away immediately or async.
    142    mStreamControl->CloseAll();
    143  } else {
    144    // We cannot interact with the child, let's just clear our lists of
    145    // streams to unblock shutdown.
    146    if (NS_WARN_IF(mStreamControl)) {
    147      // TODO: Check if this case is actually possible. We might see a late
    148      // delivery of the CSCP::ActorDestroy? What would that mean for CanSend?
    149      mStreamControl->LostIPCCleanup(SafeRefPtrFromThis());
    150      mStreamControl = nullptr;
    151    } else {
    152      NoteClosedAll();
    153    }
    154  }
    155 }
    156 
    157 void StreamList::Cancel() {
    158  NS_ASSERT_OWNINGTHREAD(StreamList);
    159  CloseAll();
    160 }
    161 
    162 bool StreamList::MatchesCacheId(CacheId aCacheId) const {
    163  NS_ASSERT_OWNINGTHREAD(StreamList);
    164  return aCacheId == mCacheId;
    165 }
    166 
    167 void StreamList::DoStringify(nsACString& aData) {
    168  aData.Append("StreamList "_ns + kStringifyStartInstance +
    169               //
    170               "List:"_ns +
    171               IntToCString(static_cast<uint64_t>(mList.Length())) +
    172               kStringifyDelimiter +
    173               //
    174               "Activated:"_ns + IntToCString(mActivated) + ")"_ns +
    175               kStringifyDelimiter +
    176               //
    177               "Manager:"_ns + IntToCString(static_cast<bool>(mManager)));
    178  if (mManager) {
    179    aData.Append(" "_ns);
    180    mManager->Stringify(aData);
    181  }
    182  aData.Append(kStringifyDelimiter +
    183               //
    184               "Context:"_ns + IntToCString(static_cast<bool>(mContext)));
    185  if (mContext) {
    186    aData.Append(" "_ns);
    187    mContext->Stringify(aData);
    188  }
    189  aData.Append(kStringifyEndInstance);
    190 }
    191 
    192 StreamList::~StreamList() {
    193  NS_ASSERT_OWNINGTHREAD(StreamList);
    194  MOZ_DIAGNOSTIC_ASSERT(!mStreamControl);
    195  if (mActivated) {
    196    mManager->RemoveStreamList(*this);
    197    for (uint32_t i = 0; i < mList.Length(); ++i) {
    198      mManager->ReleaseBodyId(mList[i].mId);
    199    }
    200    mManager->ReleaseCacheId(mCacheId);
    201  }
    202  mContext->RemoveActivity(*this);
    203 }
    204 
    205 }  // namespace mozilla::dom::cache