Backed out changeset 1d9301697aa0 (bug 1887752) for causing failures on browser_all_f...
[gecko.git] / dom / cache / StreamList.cpp
blobcbce695b60d0459c5b62041a623bd35ffc944968
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/. */
7 #include "mozilla/dom/cache/StreamList.h"
9 #include <algorithm>
10 #include "mozilla/dom/cache/CacheStreamControlParent.h"
11 #include "mozilla/dom/cache/Context.h"
12 #include "mozilla/dom/cache/Manager.h"
13 #include "nsIInputStream.h"
15 namespace mozilla::dom::cache {
17 namespace {
19 auto MatchById(const nsID& aId) {
20 return [aId](const auto& entry) { return entry.mId == aId; };
23 } // namespace
25 StreamList::StreamList(SafeRefPtr<Manager> aManager,
26 SafeRefPtr<Context> aContext)
27 : mManager(std::move(aManager)),
28 mContext(std::move(aContext)),
29 mCacheId(INVALID_CACHE_ID),
30 mStreamControl(nullptr),
31 mActivated(false) {
32 MOZ_DIAGNOSTIC_ASSERT(mManager);
33 mContext->AddActivity(*this);
36 Manager& StreamList::GetManager() const {
37 MOZ_DIAGNOSTIC_ASSERT(mManager);
38 return *mManager;
41 bool StreamList::ShouldOpenStreamFor(const nsID& aId) const {
42 NS_ASSERT_OWNINGTHREAD(StreamList);
44 return std::any_of(mList.cbegin(), mList.cend(), MatchById(aId));
47 void StreamList::SetStreamControl(CacheStreamControlParent* aStreamControl) {
48 NS_ASSERT_OWNINGTHREAD(StreamList);
49 MOZ_DIAGNOSTIC_ASSERT(aStreamControl);
51 // For cases where multiple streams are serialized for a single list
52 // then the control will get passed multiple times. This is ok, but
53 // it should be the same control each time.
54 if (mStreamControl) {
55 MOZ_DIAGNOSTIC_ASSERT(aStreamControl == mStreamControl);
56 return;
59 mStreamControl = aStreamControl;
60 mStreamControl->SetStreamList(SafeRefPtrFromThis());
63 void StreamList::RemoveStreamControl(CacheStreamControlParent* aStreamControl) {
64 NS_ASSERT_OWNINGTHREAD(StreamList);
65 MOZ_DIAGNOSTIC_ASSERT(mStreamControl);
66 MOZ_DIAGNOSTIC_ASSERT(mStreamControl == aStreamControl);
67 mStreamControl = nullptr;
70 void StreamList::Activate(CacheId aCacheId) {
71 NS_ASSERT_OWNINGTHREAD(StreamList);
72 MOZ_DIAGNOSTIC_ASSERT(!mActivated);
73 MOZ_DIAGNOSTIC_ASSERT(mCacheId == INVALID_CACHE_ID);
74 mActivated = true;
75 mCacheId = aCacheId;
76 mManager->AddRefCacheId(mCacheId);
77 mManager->AddStreamList(*this);
79 for (uint32_t i = 0; i < mList.Length(); ++i) {
80 mManager->AddRefBodyId(mList[i].mId);
84 void StreamList::Add(const nsID& aId, nsCOMPtr<nsIInputStream>&& aStream) {
85 // All streams should be added on IO thread before we set the stream
86 // control on the owning IPC thread.
87 MOZ_DIAGNOSTIC_ASSERT(!mStreamControl);
89 // Removal of the stream will be triggered when the stream is closed,
90 // which happens only once, so let's ensure nobody adds us twice.
91 MOZ_ASSERT_DEBUG_OR_FUZZING(
92 std::find_if(mList.begin(), mList.end(), MatchById(aId)) == mList.end());
94 mList.EmplaceBack(aId, std::move(aStream));
97 already_AddRefed<nsIInputStream> StreamList::Extract(const nsID& aId) {
98 NS_ASSERT_OWNINGTHREAD(StreamList);
100 const auto it = std::find_if(mList.begin(), mList.end(), MatchById(aId));
102 // Note that if the stream has not been opened with OpenMode::Eager we will
103 // find it nullptr here and it will have to be opened by the consumer.
105 return it != mList.end() ? it->mStream.forget() : nullptr;
108 void StreamList::NoteClosed(const nsID& aId) {
109 NS_ASSERT_OWNINGTHREAD(StreamList);
111 const auto it = std::find_if(mList.begin(), mList.end(), MatchById(aId));
112 if (it != mList.end()) {
113 MOZ_ASSERT(!it->mStream, "We expect to find mStream already extracted.");
114 mList.RemoveElementAt(it);
115 mManager->ReleaseBodyId(aId);
118 if (mList.IsEmpty() && mStreamControl) {
119 mStreamControl->Shutdown();
123 void StreamList::NoteClosedAll() {
124 NS_ASSERT_OWNINGTHREAD(StreamList);
125 for (uint32_t i = 0; i < mList.Length(); ++i) {
126 mManager->ReleaseBodyId(mList[i].mId);
128 mList.Clear();
130 if (mStreamControl) {
131 mStreamControl->Shutdown();
135 void StreamList::CloseAll() {
136 NS_ASSERT_OWNINGTHREAD(StreamList);
138 if (mStreamControl && mStreamControl->CanSend()) {
139 auto* streamControl = std::exchange(mStreamControl, nullptr);
141 streamControl->CloseAll();
143 mStreamControl = std::exchange(streamControl, nullptr);
145 mStreamControl->Shutdown();
146 } else {
147 // We cannot interact with the child, let's just clear our lists of
148 // streams to unblock shutdown.
149 if (NS_WARN_IF(mStreamControl)) {
150 // TODO: Check if this case is actually possible. We might see a late
151 // delivery of the CSCP::ActorDestroy? What would that mean for CanSend?
152 mStreamControl->LostIPCCleanup(SafeRefPtrFromThis());
153 mStreamControl = nullptr;
154 } else {
155 NoteClosedAll();
160 void StreamList::Cancel() {
161 NS_ASSERT_OWNINGTHREAD(StreamList);
162 CloseAll();
165 bool StreamList::MatchesCacheId(CacheId aCacheId) const {
166 NS_ASSERT_OWNINGTHREAD(StreamList);
167 return aCacheId == mCacheId;
170 void StreamList::DoStringify(nsACString& aData) {
171 aData.Append("StreamList "_ns + kStringifyStartInstance +
173 "List:"_ns +
174 IntToCString(static_cast<uint64_t>(mList.Length())) +
175 kStringifyDelimiter +
177 "Activated:"_ns + IntToCString(mActivated) + ")"_ns +
178 kStringifyDelimiter +
180 "Manager:"_ns + IntToCString(static_cast<bool>(mManager)));
181 if (mManager) {
182 aData.Append(" "_ns);
183 mManager->Stringify(aData);
185 aData.Append(kStringifyDelimiter +
187 "Context:"_ns + IntToCString(static_cast<bool>(mContext)));
188 if (mContext) {
189 aData.Append(" "_ns);
190 mContext->Stringify(aData);
192 aData.Append(kStringifyEndInstance);
195 StreamList::~StreamList() {
196 NS_ASSERT_OWNINGTHREAD(StreamList);
197 MOZ_DIAGNOSTIC_ASSERT(!mStreamControl);
198 if (mActivated) {
199 mManager->RemoveStreamList(*this);
200 for (uint32_t i = 0; i < mList.Length(); ++i) {
201 mManager->ReleaseBodyId(mList[i].mId);
203 mManager->ReleaseCacheId(mCacheId);
205 mContext->RemoveActivity(*this);
208 } // namespace mozilla::dom::cache