/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/cache/StreamList.h" #include #include "mozilla/dom/cache/CacheStreamControlParent.h" #include "mozilla/dom/cache/Context.h" #include "mozilla/dom/cache/Manager.h" #include "nsIInputStream.h" namespace mozilla::dom::cache { namespace { auto MatchById(const nsID& aId) { return [aId](const auto& entry) { return entry.mId == aId; }; } } // namespace StreamList::StreamList(SafeRefPtr aManager, SafeRefPtr aContext) : mManager(std::move(aManager)), mContext(std::move(aContext)), mCacheId(INVALID_CACHE_ID), mStreamControl(nullptr), mActivated(false) { MOZ_DIAGNOSTIC_ASSERT(mManager); mContext->AddActivity(*this); } Manager& StreamList::GetManager() const { MOZ_DIAGNOSTIC_ASSERT(mManager); return *mManager; } bool StreamList::ShouldOpenStreamFor(const nsID& aId) const { NS_ASSERT_OWNINGTHREAD(StreamList); return std::any_of(mList.cbegin(), mList.cend(), MatchById(aId)); } void StreamList::SetStreamControl(CacheStreamControlParent* aStreamControl) { NS_ASSERT_OWNINGTHREAD(StreamList); MOZ_DIAGNOSTIC_ASSERT(aStreamControl); // For cases where multiple streams are serialized for a single list // then the control will get passed multiple times. This is ok, but // it should be the same control each time. if (mStreamControl) { MOZ_DIAGNOSTIC_ASSERT(aStreamControl == mStreamControl); return; } mStreamControl = aStreamControl; mStreamControl->SetStreamList(SafeRefPtrFromThis()); } void StreamList::RemoveStreamControl(CacheStreamControlParent* aStreamControl) { NS_ASSERT_OWNINGTHREAD(StreamList); MOZ_DIAGNOSTIC_ASSERT(mStreamControl); MOZ_DIAGNOSTIC_ASSERT(mStreamControl == aStreamControl); mStreamControl = nullptr; } void StreamList::Activate(CacheId aCacheId) { NS_ASSERT_OWNINGTHREAD(StreamList); MOZ_DIAGNOSTIC_ASSERT(!mActivated); MOZ_DIAGNOSTIC_ASSERT(mCacheId == INVALID_CACHE_ID); mActivated = true; mCacheId = aCacheId; mManager->AddRefCacheId(mCacheId); mManager->AddStreamList(*this); for (uint32_t i = 0; i < mList.Length(); ++i) { mManager->AddRefBodyId(mList[i].mId); } } void StreamList::Add(const nsID& aId, nsCOMPtr&& aStream) { // All streams should be added on IO thread before we set the stream // control on the owning IPC thread. MOZ_DIAGNOSTIC_ASSERT(!mStreamControl); mList.EmplaceBack(aId, std::move(aStream)); } already_AddRefed StreamList::Extract(const nsID& aId) { NS_ASSERT_OWNINGTHREAD(StreamList); const auto it = std::find_if(mList.begin(), mList.end(), MatchById(aId)); return it != mList.end() ? it->mStream.forget() : nullptr; } void StreamList::NoteClosed(const nsID& aId) { NS_ASSERT_OWNINGTHREAD(StreamList); const auto it = std::find_if(mList.begin(), mList.end(), MatchById(aId)); if (it != mList.end()) { mList.RemoveElementAt(it); mManager->ReleaseBodyId(aId); } if (mList.IsEmpty() && mStreamControl) { mStreamControl->Shutdown(); } } void StreamList::NoteClosedAll() { NS_ASSERT_OWNINGTHREAD(StreamList); for (uint32_t i = 0; i < mList.Length(); ++i) { mManager->ReleaseBodyId(mList[i].mId); } mList.Clear(); if (mStreamControl) { mStreamControl->Shutdown(); } } void StreamList::CloseAll() { NS_ASSERT_OWNINGTHREAD(StreamList); if (mStreamControl) { auto* streamControl = std::exchange(mStreamControl, nullptr); streamControl->CloseAll(); mStreamControl = std::exchange(streamControl, nullptr); mStreamControl->Shutdown(); } } void StreamList::Cancel() { NS_ASSERT_OWNINGTHREAD(StreamList); CloseAll(); } bool StreamList::MatchesCacheId(CacheId aCacheId) const { NS_ASSERT_OWNINGTHREAD(StreamList); return aCacheId == mCacheId; } StreamList::~StreamList() { NS_ASSERT_OWNINGTHREAD(StreamList); MOZ_DIAGNOSTIC_ASSERT(!mStreamControl); if (mActivated) { mManager->RemoveStreamList(*this); for (uint32_t i = 0; i < mList.Length(); ++i) { mManager->ReleaseBodyId(mList[i].mId); } mManager->ReleaseCacheId(mCacheId); } mContext->RemoveActivity(*this); } } // namespace mozilla::dom::cache