#include "content/browser/cache_storage/cache_storage_manager.h"
#include <stdint.h>
#include <map>
#include <numeric>
#include <optional>
#include <set>
#include <tuple>
#include <utility>
#include <vector>
#include "base/barrier_callback.h"
#include "base/containers/id_map.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/hash/sha1.h"
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/sequence_checker.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "components/services/storage/public/cpp/constants.h"
#include "content/browser/cache_storage/cache_storage.h"
#include "content/browser/cache_storage/cache_storage.pb.h"
#include "content/browser/cache_storage/cache_storage_quota_client.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/quota/storage_directory_util.h"
#include "storage/common/database/database_identifier.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
namespace {
bool DeleteDir(const base::FilePath& path) {
return base::DeletePathRecursively(path);
}
void DeleteBucketDidDeleteDir(
storage::mojom::QuotaClient::DeleteBucketDataCallback callback,
bool rv) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback),
rv ? blink::mojom::QuotaStatusCode::kOk
: blink::mojom::QuotaStatusCode::kErrorAbort));
}
void DidDeleteAllBuckets(
storage::mojom::QuotaClient::DeleteBucketDataCallback callback,
std::vector<blink::mojom::QuotaStatusCode> results) {
auto status = blink::mojom::QuotaStatusCode::kOk;
for (auto result : results) {
if (result != blink::mojom::QuotaStatusCode::kOk) {
status = result;
break;
}
}
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), status));
}
enum class IndexResult {
kOk = 0,
kFailedToParse = 1,
kMissingOrigin = 2,
kEmptyOriginUrl = 3,
kPathMismatch = 4,
kPathFileInfoFailed = 5,
kInvalidStorageKey = 6,
kMaxValue = kInvalidStorageKey,
};
IndexResult ValidateIndex(proto::CacheStorageIndex index) {
if (!index.has_origin()) {
return IndexResult::kMissingOrigin;
}
GURL url(index.origin());
if (url.is_empty()) {
return IndexResult::kEmptyOriginUrl;
}
return IndexResult::kOk;
}
void RecordIndexValidationResult(IndexResult value) {
base::UmaHistogramEnumeration("ServiceWorkerCache.ListOriginsIndexValidity",
value);
}
base::FilePath ConstructOriginPath(const base::FilePath& profile_path,
const url::Origin& origin,
storage::mojom::CacheStorageOwner owner) {
base::FilePath first_party_default_root_path =
CacheStorageManager::ConstructFirstPartyDefaultRootPath(profile_path);
std::string identifier = storage::GetIdentifierFromOrigin(origin);
if (owner != storage::mojom::CacheStorageOwner::kCacheAPI) {
identifier += "-" + base::NumberToString(static_cast<int>(owner));
}
const std::string origin_hash_hex =
base::HexEncodeLower(base::SHA1Hash(base::as_byte_span(identifier)));
return first_party_default_root_path.AppendASCII(origin_hash_hex);
}
void ValidateAndAddBucketFromPath(
const base::FilePath& index_file_directory_path,
storage::mojom::CacheStorageOwner owner,
const base::FilePath& profile_path,
std::vector<storage::BucketLocator>& buckets,
bool is_origin_path = false) {
if (!base::PathExists(index_file_directory_path)) {
return;
}
base::FilePath index_path =
index_file_directory_path.AppendASCII(CacheStorage::kIndexFileName);
std::string protobuf;
base::ReadFileToString(index_path, &protobuf);
proto::CacheStorageIndex index;
if (!index.ParseFromString(protobuf)) {
RecordIndexValidationResult(IndexResult::kFailedToParse);
return;
}
IndexResult rv = ValidateIndex(index);
if (rv != IndexResult::kOk) {
RecordIndexValidationResult(rv);
return;
}
blink::StorageKey storage_key;
if (index.has_storage_key()) {
std::optional<blink::StorageKey> result =
blink::StorageKey::Deserialize(index.storage_key());
if (!result) {
RecordIndexValidationResult(IndexResult::kInvalidStorageKey);
return;
}
storage_key = result.value();
} else {
storage_key = blink::StorageKey::CreateFirstParty(
url::Origin::Create(GURL(index.origin())));
}
DCHECK(!storage_key.origin().GetURL().is_empty());
storage::BucketLocator bucket_locator{};
if (index.has_bucket_id() && index.has_bucket_is_default()) {
bucket_locator =
storage::BucketLocator(storage::BucketId(index.bucket_id()),
storage_key, index.bucket_is_default());
} else {
bucket_locator = storage::BucketLocator::ForDefaultBucket(storage_key);
}
auto bucket_path = CacheStorageManager::ConstructBucketPath(
profile_path, bucket_locator, owner);
if (index_file_directory_path != bucket_path) {
if (is_origin_path) {
storage::mojom::CacheStorageOwner other_owner =
owner == storage::mojom::CacheStorageOwner::kCacheAPI
? storage::mojom::CacheStorageOwner::kBackgroundFetch
: storage::mojom::CacheStorageOwner::kCacheAPI;
auto other_owner_path = CacheStorageManager::ConstructBucketPath(
profile_path, bucket_locator, other_owner);
if (index_file_directory_path == other_owner_path) {
return;
}
}
RecordIndexValidationResult(IndexResult::kPathMismatch);
return;
}
buckets.emplace_back(bucket_locator);
RecordIndexValidationResult(IndexResult::kOk);
}
void GetBucketsFromDiskOnTaskRunner(
scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
std::vector<storage::BucketLocator> buckets,
base::FilePath profile_path,
storage::mojom::CacheStorageOwner owner,
base::OnceCallback<void(std::vector<storage::BucketLocator>)> callback) {
{
base::FilePath first_party_default_buckets_root_path =
CacheStorageManager::ConstructFirstPartyDefaultRootPath(profile_path);
base::FileEnumerator file_enum(first_party_default_buckets_root_path,
false ,
base::FileEnumerator::DIRECTORIES);
base::FilePath path;
while (!(path = file_enum.Next()).empty()) {
ValidateAndAddBucketFromPath(path, owner, profile_path, buckets,
true );
}
}
base::FilePath third_party_and_non_default_root_path =
CacheStorageManager::ConstructThirdPartyAndNonDefaultRootPath(
profile_path);
{
base::FileEnumerator file_enum(third_party_and_non_default_root_path,
false ,
base::FileEnumerator::DIRECTORIES);
base::FilePath path;
while (!(path = file_enum.Next()).empty()) {
base::FilePath cache_storage_path =
owner == storage::mojom::CacheStorageOwner::kCacheAPI
? path.Append(storage::kCacheStorageDirectory)
: path.Append(storage::kBackgroundFetchDirectory);
if (!base::PathExists(cache_storage_path)) {
continue;
}
ValidateAndAddBucketFromPath(cache_storage_path, owner, profile_path,
buckets);
}
}
scheduler_task_runner->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(buckets)));
return;
}
bool BucketMatchesOriginsForDeletion(
const storage::BucketLocator& bucket_locator,
const std::set<url::Origin>& origins) {
auto& bucket_key = bucket_locator.storage_key;
for (auto& requested_origin : origins) {
if (bucket_key.origin() == requested_origin ||
(bucket_key.IsThirdPartyContext() &&
bucket_key.top_level_site().IsSameSiteWith(requested_origin))) {
return true;
}
}
return false;
}
}
scoped_refptr<CacheStorageManager> CacheStorageManager::Create(
const base::FilePath& profile_path,
scoped_refptr<base::SequencedTaskRunner> cache_task_runner,
scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
base::WeakPtr<CacheStorageDispatcherHost> cache_storage_dispatcher_host) {
DCHECK(cache_task_runner);
DCHECK(scheduler_task_runner);
DCHECK(quota_manager_proxy);
DCHECK(blob_storage_context);
return base::WrapRefCounted(new CacheStorageManager(
profile_path, std::move(cache_task_runner),
std::move(scheduler_task_runner), std::move(quota_manager_proxy),
std::move(blob_storage_context),
std::move(cache_storage_dispatcher_host)));
}
scoped_refptr<CacheStorageManager> CacheStorageManager::CreateForTesting(
CacheStorageManager* old_manager) {
scoped_refptr<CacheStorageManager> manager(new CacheStorageManager(
old_manager->profile_path(), old_manager->cache_task_runner(),
old_manager->scheduler_task_runner(), old_manager->quota_manager_proxy_,
old_manager->blob_storage_context_,
old_manager->cache_storage_dispatcher_host_));
return manager;
}
CacheStorageManager::~CacheStorageManager() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
#if DCHECK_IS_ON()
bool CacheStorageManager::CacheStoragePathIsUnique(const base::FilePath& path) {
for (const auto& bucket_info : cache_storage_map_) {
const auto& bucket_locator = bucket_info.first.first;
const auto owner = bucket_info.first.second;
if (path == CacheStorageManager::ConstructBucketPath(
profile_path_, bucket_locator, owner)) {
return false;
}
}
return true;
}
#endif
bool CacheStorageManager::ConflictingInstanceExistsInMap(
storage::mojom::CacheStorageOwner owner,
const storage::BucketLocator& bucket_locator) {
if (IsMemoryBacked() || !bucket_locator.is_default ||
!bucket_locator.storage_key.IsFirstPartyContext()) {
return false;
}
CacheStorageMap::const_iterator it =
cache_storage_map_.find({bucket_locator, owner});
if (it != cache_storage_map_.end()) {
return false;
}
for (const auto& key_value : cache_storage_map_) {
if (key_value.first.second != owner) {
continue;
}
if (!key_value.first.first.is_default ||
key_value.first.first.storage_key != bucket_locator.storage_key) {
continue;
}
return true;
}
return false;
}
CacheStorageHandle CacheStorageManager::OpenCacheStorage(
const storage::BucketLocator& bucket_locator,
storage::mojom::CacheStorageOwner owner) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!memory_pressure_listener_registration_) {
memory_pressure_listener_registration_ =
std::make_unique<base::AsyncMemoryPressureListenerRegistration>(
FROM_HERE, base::MemoryPressureListenerTag::kCacheStorageManager,
this);
}
CacheStorageMap::const_iterator it =
cache_storage_map_.find({bucket_locator, owner});
if (it == cache_storage_map_.end()) {
const auto bucket_path = CacheStorageManager::ConstructBucketPath(
profile_path_, bucket_locator, owner);
#if DCHECK_IS_ON()
DLOG_IF(WARNING, !CacheStoragePathIsUnique(bucket_path))
<< "Multiple CacheStorage instances using the same directory detected";
#endif
CacheStorage* cache_storage = new CacheStorage(
bucket_path, IsMemoryBacked(), cache_task_runner_.get(),
scheduler_task_runner_, quota_manager_proxy_, blob_storage_context_,
this, bucket_locator, owner);
cache_storage_map_[{bucket_locator, owner}] =
base::WrapUnique(cache_storage);
return cache_storage->CreateHandle();
}
return it->second.get()->CreateHandle();
}
void CacheStorageManager::NotifyCacheListChanged(
const storage::BucketLocator& bucket_locator) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (const auto& observer : observers_) {
observer->OnCacheListChanged(bucket_locator);
}
}
void CacheStorageManager::NotifyCacheContentChanged(
const storage::BucketLocator& bucket_locator,
const std::u16string& name) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (const auto& observer : observers_) {
observer->OnCacheContentChanged(bucket_locator, base::UTF16ToUTF8(name));
}
}
void CacheStorageManager::CacheStorageUnreferenced(
CacheStorage* cache_storage,
const storage::BucketLocator& bucket_locator,
storage::mojom::CacheStorageOwner owner) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(cache_storage);
cache_storage->AssertUnreferenced();
auto it = cache_storage_map_.find({bucket_locator, owner});
CHECK(it != cache_storage_map_.end());
DCHECK(it->second.get() == cache_storage);
}
void CacheStorageManager::GetBucketUsage(
const storage::BucketLocator& bucket_locator,
storage::mojom::CacheStorageOwner owner,
storage::mojom::QuotaClient::GetBucketUsageCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (IsMemoryBacked()) {
auto it = cache_storage_map_.find({bucket_locator, owner});
if (it == cache_storage_map_.end()) {
scheduler_task_runner_->PostTask(FROM_HERE,
base::BindOnce(std::move(callback),
0));
return;
}
CacheStorageHandle cache_storage = OpenCacheStorage(bucket_locator, owner);
CacheStorage::From(cache_storage)->Size(std::move(callback));
return;
}
cache_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&base::PathExists,
CacheStorageManager::ConstructBucketPath(
profile_path_, bucket_locator, owner)),
base::BindOnce(&CacheStorageManager::GetBucketUsageDidGetExists,
weak_ptr_factory_.GetWeakPtr(), bucket_locator, owner,
std::move(callback)));
}
void CacheStorageManager::GetBucketUsageDidGetExists(
const storage::BucketLocator& bucket_locator,
storage::mojom::CacheStorageOwner owner,
storage::mojom::QuotaClient::GetBucketUsageCallback callback,
bool exists) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!exists || ConflictingInstanceExistsInMap(owner, bucket_locator)) {
scheduler_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), 0));
return;
}
CacheStorageHandle cache_storage = OpenCacheStorage(bucket_locator, owner);
CacheStorage::From(cache_storage)->Size(std::move(callback));
}
void CacheStorageManager::GetStorageKeys(
storage::mojom::CacheStorageOwner owner,
storage::mojom::QuotaClient::GetDefaultStorageKeysCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (IsMemoryBacked()) {
std::vector<blink::StorageKey> storage_keys;
for (const auto& key_value : cache_storage_map_) {
if (key_value.first.second != owner) {
continue;
}
const storage::BucketLocator& bucket_locator = key_value.first.first;
if (!bucket_locator.is_default) {
continue;
}
storage_keys.push_back(bucket_locator.storage_key);
}
scheduler_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), std::move(storage_keys)));
return;
}
std::vector<storage::BucketLocator> buckets;
cache_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&GetBucketsFromDiskOnTaskRunner,
base::WrapRefCounted(scheduler_task_runner_.get()),
std::move(buckets), profile_path_, owner,
base::BindOnce(&CacheStorageManager::ListStorageKeysOnTaskRunner,
weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
}
void CacheStorageManager::DeleteOriginsDataGotAllBucketInfo(
const std::set<url::Origin>& origins,
storage::mojom::CacheStorageOwner owner,
base::OnceCallback<void(blink::mojom::QuotaStatusCode)> callback,
std::vector<storage::BucketLocator> buckets) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (buckets.empty()) {
scheduler_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback),
blink::mojom::QuotaStatusCode::kOk));
return;
}
const auto barrier_callback =
base::BarrierCallback<blink::mojom::QuotaStatusCode>(
buckets.size(),
base::BindOnce(&DidDeleteAllBuckets, std::move(callback)));
for (const storage::BucketLocator& bucket_locator : buckets) {
if (!BucketMatchesOriginsForDeletion(bucket_locator, origins)) {
barrier_callback.Run(blink::mojom::QuotaStatusCode::kOk);
continue;
}
if (!bucket_locator.is_null()) {
DeleteBucketDataDidGetExists(owner, barrier_callback, bucket_locator,
true);
} else {
cache_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&DeleteDir, CacheStorageManager::ConstructBucketPath(
profile_path_, bucket_locator, owner)),
base::BindOnce(&DeleteBucketDidDeleteDir, barrier_callback));
}
}
}
void CacheStorageManager::DeleteOriginData(
const std::set<url::Origin>& origins,
storage::mojom::CacheStorageOwner owner,
storage::mojom::QuotaClient::DeleteBucketDataCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (origins.empty()) {
scheduler_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback),
blink::mojom::QuotaStatusCode::kOk));
return;
}
if (IsMemoryBacked()) {
std::vector<storage::BucketLocator> to_delete;
to_delete.reserve(origins.size());
for (const auto& key_value : cache_storage_map_) {
if (key_value.first.second != owner) {
continue;
}
to_delete.emplace_back(key_value.first.first);
}
DeleteOriginsDataGotAllBucketInfo(origins, owner, std::move(callback),
std::move(to_delete));
return;
}
std::vector<storage::BucketLocator> buckets;
cache_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&GetBucketsFromDiskOnTaskRunner,
base::WrapRefCounted(scheduler_task_runner_.get()),
std::move(buckets), profile_path_, owner,
base::BindOnce(
&CacheStorageManager::DeleteOriginsDataGotAllBucketInfo,
weak_ptr_factory_.GetWeakPtr(), origins, owner,
std::move(callback))));
}
void CacheStorageManager::DeleteBucketData(
const storage::BucketLocator& bucket_locator,
storage::mojom::CacheStorageOwner owner,
storage::mojom::QuotaClient::DeleteBucketDataCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (cache_storage_dispatcher_host_) {
cache_storage_dispatcher_host_->NotifyBucketDataDeleted(bucket_locator);
}
if (IsMemoryBacked()) {
auto it = cache_storage_map_.find({bucket_locator, owner});
if (it == cache_storage_map_.end()) {
scheduler_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback),
blink::mojom::QuotaStatusCode::kOk));
return;
}
DeleteBucketDataDidGetExists(owner, std::move(callback), bucket_locator,
true);
return;
}
cache_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&base::PathExists,
CacheStorageManager::ConstructBucketPath(
profile_path_, bucket_locator, owner)),
base::BindOnce(&CacheStorageManager::DeleteBucketDataDidGetExists,
weak_ptr_factory_.GetWeakPtr(), owner, std::move(callback),
bucket_locator));
}
void CacheStorageManager::DeleteBucketDataDidGetExists(
storage::mojom::CacheStorageOwner owner,
storage::mojom::QuotaClient::DeleteBucketDataCallback callback,
storage::BucketLocator bucket_locator,
bool exists) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!exists || ConflictingInstanceExistsInMap(owner, bucket_locator)) {
scheduler_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback),
blink::mojom::QuotaStatusCode::kOk));
return;
}
CacheStorageHandle handle = OpenCacheStorage(bucket_locator, owner);
auto it = cache_storage_map_.find({bucket_locator, owner});
CHECK(it != cache_storage_map_.end());
CacheStorage* cache_storage = it->second.release();
cache_storage->ResetManager();
cache_storage_map_.erase({bucket_locator, owner});
cache_storage->GetSizeThenCloseAllCaches(
base::BindOnce(&CacheStorageManager::DeleteBucketDidClose,
weak_ptr_factory_.GetWeakPtr(), bucket_locator, owner,
std::move(callback), base::WrapUnique(cache_storage)));
}
void CacheStorageManager::AddObserver(
mojo::PendingRemote<storage::mojom::CacheStorageObserver> observer) {
observers_.Add(std::move(observer));
}
void CacheStorageManager::DeleteBucketDidClose(
const storage::BucketLocator& bucket_locator,
storage::mojom::CacheStorageOwner owner,
storage::mojom::QuotaClient::DeleteBucketDataCallback callback,
std::unique_ptr<CacheStorage> cache_storage,
int64_t bucket_size) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
cache_storage.reset();
quota_manager_proxy_->NotifyBucketModified(
CacheStorageQuotaClient::GetClientTypeFromOwner(owner), bucket_locator,
-bucket_size, base::Time::Now(),
base::SequencedTaskRunner::GetCurrentDefault(), base::DoNothing());
if (owner == storage::mojom::CacheStorageOwner::kCacheAPI) {
NotifyCacheListChanged(bucket_locator);
}
if (IsMemoryBacked()) {
scheduler_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback),
blink::mojom::QuotaStatusCode::kOk));
return;
}
cache_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&DeleteDir, CacheStorageManager::ConstructBucketPath(
profile_path_, bucket_locator, owner)),
base::BindOnce(&DeleteBucketDidDeleteDir, std::move(callback)));
}
CacheStorageManager::CacheStorageManager(
const base::FilePath& profile_path,
scoped_refptr<base::SequencedTaskRunner> cache_task_runner,
scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
base::WeakPtr<CacheStorageDispatcherHost> cache_storage_dispatcher_host)
: profile_path_(profile_path),
cache_task_runner_(std::move(cache_task_runner)),
scheduler_task_runner_(std::move(scheduler_task_runner)),
quota_manager_proxy_(std::move(quota_manager_proxy)),
blob_storage_context_(std::move(blob_storage_context)),
cache_storage_dispatcher_host_(std::move(cache_storage_dispatcher_host)) {
DCHECK(cache_task_runner_);
DCHECK(scheduler_task_runner_);
DCHECK(quota_manager_proxy_);
DCHECK(blob_storage_context_);
}
base::FilePath CacheStorageManager::ConstructBucketPath(
const base::FilePath& profile_path,
const storage::BucketLocator& bucket_locator,
storage::mojom::CacheStorageOwner owner) {
if (bucket_locator.is_default &&
bucket_locator.storage_key.IsFirstPartyContext()) {
return ConstructOriginPath(profile_path,
bucket_locator.storage_key.origin(), owner);
}
switch (owner) {
case storage::mojom::CacheStorageOwner::kCacheAPI:
return storage::CreateClientBucketPath(
profile_path, bucket_locator,
storage::QuotaClientType::kServiceWorkerCache);
case storage::mojom::CacheStorageOwner::kBackgroundFetch:
return storage::CreateClientBucketPath(
profile_path, bucket_locator,
storage::QuotaClientType::kBackgroundFetch);
default:
NOTREACHED();
}
}
bool CacheStorageManager::IsValidQuotaStorageKey(
const blink::StorageKey& storage_key) {
return !storage_key.origin().opaque();
}
void CacheStorageManager::OnMemoryPressure(base::MemoryPressureLevel level) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (level != base::MEMORY_PRESSURE_LEVEL_CRITICAL) {
return;
}
for (auto& entry : cache_storage_map_) {
entry.second->ReleaseUnreferencedCaches();
}
}
base::FilePath CacheStorageManager::ConstructFirstPartyDefaultRootPath(
const base::FilePath& profile_path) {
return profile_path.Append(storage::kServiceWorkerDirectory)
.Append(storage::kCacheStorageDirectory);
}
base::FilePath CacheStorageManager::ConstructThirdPartyAndNonDefaultRootPath(
const base::FilePath& profile_path) {
return profile_path.Append(storage::kWebStorageDirectory);
}
void CacheStorageManager::ListStorageKeysOnTaskRunner(
storage::mojom::QuotaClient::GetDefaultStorageKeysCallback callback,
std::vector<storage::BucketLocator> buckets) {
std::vector<blink::StorageKey> out_storage_keys;
for (const storage::BucketLocator& bucket_locator : buckets) {
if (!bucket_locator.is_default) {
continue;
}
out_storage_keys.emplace_back(bucket_locator.storage_key);
}
scheduler_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), std::move(out_storage_keys)));
}
}