#ifndef CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_H_
#define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "build/build_config.h"
#include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
#include "content/browser/cache_storage/blob_storage_context_wrapper.h"
#include "content/browser/cache_storage/cache_storage_cache.h"
#include "content/browser/cache_storage/cache_storage_cache_observer.h"
#include "content/browser/cache_storage/cache_storage_handle.h"
#include "content/browser/cache_storage/cache_storage_manager.h"
#include "content/browser/cache_storage/cache_storage_scheduler_types.h"
#include "content/common/content_export.h"
#include "storage/browser/quota/quota_manager.h"
#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/application_status_listener.h"
#endif
namespace base {
class SequencedTaskRunner;
}
namespace content {
class CacheStorageIndex;
class CacheStorageScheduler;
class CacheStorageManager;
namespace cache_storage_manager_unittest {
class CacheStorageManagerTest;
FORWARD_DECLARE_TEST(CacheStorageManagerTest, PersistedCacheKeyUsed);
FORWARD_DECLARE_TEST(CacheStorageManagerTest, PutResponseWithExistingFileTest);
FORWARD_DECLARE_TEST(CacheStorageManagerTest, TestErrorInitializingCache);
}
class CONTENT_EXPORT CacheStorage : public CacheStorageCacheObserver {
public:
constexpr static int64_t kSizeUnknown = -1;
using SizeCallback = base::OnceCallback<void(int64_t)>;
using BoolAndErrorCallback =
base::OnceCallback<void(bool, blink::mojom::CacheStorageError)>;
using ErrorCallback =
base::OnceCallback<void(blink::mojom::CacheStorageError)>;
using CacheAndErrorCallback =
base::OnceCallback<void(CacheStorageCacheHandle,
blink::mojom::CacheStorageError)>;
using EnumerateCachesCallback =
base::OnceCallback<void(std::vector<std::u16string> cache_names)>;
static const char kIndexFileName[];
CacheStorage(const base::FilePath& origin_path,
bool memory_only,
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,
CacheStorageManager* cache_storage_manager,
const storage::BucketLocator& bucket_locator,
storage::mojom::CacheStorageOwner owner);
CacheStorage(const CacheStorage&) = delete;
CacheStorage& operator=(const CacheStorage&) = delete;
virtual ~CacheStorage();
CacheStorageHandle CreateHandle();
void AddHandleRef();
void DropHandleRef();
void AssertUnreferenced() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!handle_ref_count_);
}
void Init();
void OpenCache(const std::u16string& cache_name,
int64_t trace_id,
CacheAndErrorCallback callback);
void HasCache(const std::u16string& cache_name,
int64_t trace_id,
BoolAndErrorCallback callback);
void DoomCache(const std::u16string& cache_name,
int64_t trace_id,
ErrorCallback callback);
void EnumerateCaches(int64_t trace_id, EnumerateCachesCallback callback);
void MatchCache(const std::u16string& cache_name,
blink::mojom::FetchAPIRequestPtr request,
blink::mojom::CacheQueryOptionsPtr match_options,
CacheStorageSchedulerPriority priority,
int64_t trace_id,
CacheStorageCache::ResponseCallback callback);
void MatchAllCaches(blink::mojom::FetchAPIRequestPtr request,
blink::mojom::CacheQueryOptionsPtr match_options,
CacheStorageSchedulerPriority priority,
int64_t trace_id,
CacheStorageCache::ResponseCallback callback);
void WriteToCache(const std::u16string& cache_name,
blink::mojom::FetchAPIRequestPtr request,
blink::mojom::FetchAPIResponsePtr response,
int64_t trace_id,
ErrorCallback callback);
void GetSizeThenCloseAllCaches(SizeCallback callback);
void Size(SizeCallback callback);
CacheStorageSchedulerId StartAsyncOperationForTesting();
void CompleteAsyncOperationForTesting(CacheStorageSchedulerId id);
void ResetManager();
void CacheSizeUpdated(const CacheStorageCache* cache) override;
void ReleaseUnreferencedCaches();
static CacheStorage* From(const CacheStorageHandle& handle) {
return static_cast<CacheStorage*>(handle.value());
}
static std::u16string ConvertUTF16BytesStringToU16String(
const std::string& utf16_bytes,
bool correct_encoding);
protected:
virtual void CacheUnreferenced(CacheStorageCache* cache);
private:
friend class CacheStorageCache;
friend class cache_storage_manager_unittest::CacheStorageManagerTest;
FRIEND_TEST_ALL_PREFIXES(
cache_storage_manager_unittest::CacheStorageManagerTest,
PersistedCacheKeyUsed);
FRIEND_TEST_ALL_PREFIXES(
cache_storage_manager_unittest::CacheStorageManagerTest,
PutResponseWithExistingFileTest);
FRIEND_TEST_ALL_PREFIXES(
cache_storage_manager_unittest::CacheStorageManagerTest,
TestErrorInitializingCache);
class CacheLoader;
class MemoryLoader;
class SimpleCacheLoader;
struct CacheMatchResponse;
typedef std::map<std::u16string, std::unique_ptr<CacheStorageCache>> CacheMap;
static void GenerateNewKeyForTesting();
CacheStorageCacheHandle GetLoadedCache(const std::u16string& cache_name);
void LazyInit();
void LazyInitImpl();
void LazyInitDidLoadIndex(std::unique_ptr<CacheStorageIndex> index);
void OpenCacheImpl(const std::u16string& cache_name,
int64_t trace_id,
CacheAndErrorCallback callback);
void CreateCacheDidCreateCache(const std::u16string& cache_name,
int64_t trace_id,
CacheAndErrorCallback callback,
std::unique_ptr<CacheStorageCache> cache,
blink::mojom::CacheStorageError status);
void CreateCacheDidWriteIndex(CacheAndErrorCallback callback,
CacheStorageCacheHandle cache_handle,
int64_t trace_id,
bool success);
void HasCacheImpl(const std::u16string& cache_name,
int64_t trace_id,
BoolAndErrorCallback callback);
void DoomCacheImpl(const std::u16string& cache_name,
int64_t trace_id,
ErrorCallback callback);
void DeleteCacheDidWriteIndex(CacheStorageCacheHandle cache_handle,
ErrorCallback callback,
int64_t trace_id,
bool success);
void DeleteCacheFinalize(CacheStorageCache* doomed_cache);
void DeleteCacheDidGetSize(CacheStorageCache* doomed_cache,
int64_t cache_size);
void DeleteCacheDidCleanUp(bool success);
void EnumerateCachesImpl(int64_t trace_id, EnumerateCachesCallback callback);
void MatchCacheImpl(const std::u16string& cache_name,
blink::mojom::FetchAPIRequestPtr request,
blink::mojom::CacheQueryOptionsPtr match_options,
CacheStorageSchedulerPriority priority,
int64_t trace_id,
CacheStorageCache::ResponseCallback callback);
void MatchCacheDidMatch(CacheStorageCacheHandle cache_handle,
int64_t trace_id,
CacheStorageCache::ResponseCallback callback,
blink::mojom::CacheStorageError error,
blink::mojom::FetchAPIResponsePtr response);
void MatchAllCachesImpl(blink::mojom::FetchAPIRequestPtr request,
blink::mojom::CacheQueryOptionsPtr match_options,
CacheStorageSchedulerPriority priority,
int64_t trace_id,
CacheStorageCache::ResponseCallback callback);
void MatchAllCachesDidMatch(CacheStorageCacheHandle cache_handle,
CacheMatchResponse* out_match_response,
const base::RepeatingClosure& barrier_closure,
int64_t trace_id,
blink::mojom::CacheStorageError error,
blink::mojom::FetchAPIResponsePtr response);
void MatchAllCachesDidMatchAll(
std::unique_ptr<std::vector<CacheMatchResponse>> match_responses,
int64_t trace_id,
CacheStorageCache::ResponseCallback callback);
void WriteToCacheImpl(const std::u16string& cache_name,
blink::mojom::FetchAPIRequestPtr request,
blink::mojom::FetchAPIResponsePtr response,
int64_t trace_id,
ErrorCallback callback);
void GetSizeThenCloseAllCachesImpl(SizeCallback callback);
void SizeImpl(SizeCallback callback);
void SizeRetrievedFromCache(CacheStorageCacheHandle cache_handle,
base::OnceClosure closure,
int64_t* accumulator,
int64_t size);
void NotifyCacheContentChanged(const std::u16string& cache_name);
void ScheduleWriteIndex();
void WriteIndex(base::OnceCallback<void(bool)> callback);
void WriteIndexImpl(base::OnceCallback<void(bool)> callback);
bool index_write_pending() const { return !index_write_task_.IsCancelled(); }
bool InitiateScheduledIndexWriteForTest(
base::OnceCallback<void(bool)> callback);
void FlushIndexIfDirty();
#if BUILDFLAG(IS_ANDROID)
void OnApplicationStateChange(base::android::ApplicationState state);
#endif
const storage::BucketLocator bucket_locator_;
bool initialized_ = false;
bool initializing_ = false;
const bool memory_only_;
std::unique_ptr<CacheStorageScheduler> scheduler_;
CacheMap cache_map_;
std::map<CacheStorageCache*, std::unique_ptr<CacheStorageCache>>
doomed_caches_;
std::unique_ptr<CacheStorageIndex> cache_index_;
base::FilePath directory_path_;
scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
size_t handle_ref_count_ = 0;
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
scoped_refptr<BlobStorageContextWrapper> blob_storage_context_;
const storage::mojom::CacheStorageOwner owner_;
std::unique_ptr<CacheLoader> cache_loader_;
CacheStorageSchedulerId init_id_ = -1;
raw_ptr<CacheStorageManager> cache_storage_manager_;
base::CancelableOnceClosure index_write_task_;
#if BUILDFLAG(IS_ANDROID)
std::unique_ptr<base::android::ApplicationStatusListener>
app_status_listener_;
#endif
bool app_on_background_ = false;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<CacheStorage> weak_factory_{this};
};
}
#endif