Commit aaa7db01 authored by Josh Karlin's avatar Josh Karlin Committed by Commit Bot

[CacheStorage] Doom entries before closing if they're mid-write

CacheStorageCache dooms entries before closing them if their write operations
fail. This prevents them from being used in the future. In the event that
a ScopedEntry is held by a callback and the callback never gets to run, but
does get deleted, a partially written entry would be closed and will be
reusable.

This is a hypothetical problem. We're not actually sure this can happen since
the CacheStorageCache is kept alive by its manager during async operations. But
for safety, I've made a new smart pointer for disk_cache::Entry*'s that will
by default doom an entry before closing it unless WritingCompleted() has been
called on its deleter. This new smart pointer is used anywhere that Entry*
writing occurs in CacheStorage.

Bug: 617683
Change-Id: Ia5b83bd87b4997fea08cba013fc4701441db6f42
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1600267
Commit-Queue: Josh Karlin <jkarlin@chromium.org>
Reviewed-by: default avatarBen Kelly <wanderview@chromium.org>
Reviewed-by: default avatarMaks Orlovich <morlovich@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659210}
parent a7332cd3
......@@ -609,6 +609,7 @@ jumbo_source_set("browser") {
"cache_storage/legacy/legacy_cache_storage.h",
"cache_storage/legacy/legacy_cache_storage_cache.cc",
"cache_storage/legacy/legacy_cache_storage_cache.h",
"cache_storage/scoped_writable_entry.h",
"child_process_launcher.cc",
"child_process_launcher.h",
"child_process_launcher_helper.cc",
......
......@@ -30,7 +30,7 @@ CacheStorageBlobToDiskCache::CacheStorageBlobToDiskCache()
CacheStorageBlobToDiskCache::~CacheStorageBlobToDiskCache() = default;
void CacheStorageBlobToDiskCache::StreamBlobToCache(
disk_cache::ScopedEntryPtr entry,
ScopedWritableEntry entry,
int disk_cache_body_index,
blink::mojom::BlobPtr blob,
uint64_t blob_size,
......
......@@ -11,9 +11,9 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/cache_storage/scoped_writable_entry.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/disk_cache/disk_cache.h"
#include "services/network/public/cpp/net_adapters.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
......@@ -24,7 +24,7 @@ class CONTENT_EXPORT CacheStorageBlobToDiskCache
: public blink::mojom::BlobReaderClient {
public:
using EntryAndBoolCallback =
base::OnceCallback<void(disk_cache::ScopedEntryPtr, bool)>;
base::OnceCallback<void(ScopedWritableEntry, bool)>;
// The buffer size used for reading from blobs and writing to disk cache.
static const int kBufferSize;
......@@ -35,7 +35,7 @@ class CONTENT_EXPORT CacheStorageBlobToDiskCache
// Writes the body of |blob| to |entry| with index
// |disk_cache_body_index|. |entry| is passed to the callback once complete.
// Only call this once per instantiation of CacheStorageBlobToDiskCache.
void StreamBlobToCache(disk_cache::ScopedEntryPtr entry,
void StreamBlobToCache(ScopedWritableEntry entry,
int disk_cache_body_index,
blink::mojom::BlobPtr blob,
uint64_t blob_size,
......@@ -57,7 +57,7 @@ class CONTENT_EXPORT CacheStorageBlobToDiskCache
void OnDataPipeReadable(MojoResult result);
int cache_entry_offset_ = 0;
disk_cache::ScopedEntryPtr entry_;
ScopedWritableEntry entry_;
int disk_cache_body_index_ = 0;
EntryAndBoolCallback callback_;
......
......@@ -16,6 +16,7 @@
#include "base/test/null_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/browser/cache_storage/scoped_writable_entry.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
......@@ -181,7 +182,7 @@ class CacheStorageBlobToDiskCacheTest : public testing::Test {
return callback_called_ && callback_success_;
}
void StreamCallback(disk_cache::ScopedEntryPtr entry_ptr, bool success) {
void StreamCallback(ScopedWritableEntry entry_ptr, bool success) {
disk_cache_entry_ = std::move(entry_ptr);
callback_success_ = success;
callback_called_ = true;
......@@ -194,7 +195,7 @@ class CacheStorageBlobToDiskCacheTest : public testing::Test {
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
std::unique_ptr<storage::BlobDataHandle> blob_handle_;
std::unique_ptr<disk_cache::Backend> cache_backend_;
disk_cache::ScopedEntryPtr disk_cache_entry_;
ScopedWritableEntry disk_cache_entry_;
std::unique_ptr<TestCacheStorageBlobToDiskCache>
cache_storage_blob_to_disk_cache_;
std::string data_;
......
......@@ -12,6 +12,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/cache_storage/cache_storage_cache_handle.h"
#include "content/browser/cache_storage/scoped_writable_entry.h"
#include "content/common/content_export.h"
#include "net/disk_cache/disk_cache.h"
#include "storage/browser/blob/blob_data_builder.h"
......@@ -51,7 +52,7 @@ struct PutContext {
// Provided while writing to the cache.
ErrorCallback callback;
disk_cache::ScopedEntryPtr cache_entry;
ScopedWritableEntry cache_entry;
private:
DISALLOW_COPY_AND_ASSIGN(PutContext);
......
......@@ -40,6 +40,8 @@
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "crypto/symmetric_key.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "mojo/public/cpp/system/data_pipe_drainer.h"
#include "net/base/test_completion_callback.h"
#include "net/disk_cache/disk_cache.h"
......@@ -52,6 +54,7 @@
#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/blob/blob_url_request_job_factory.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/test/fake_blob.h"
#include "storage/browser/test/mock_quota_manager_proxy.h"
#include "storage/browser/test/mock_special_storage_policy.h"
#include "storage/common/blob_storage/blob_handle.h"
......@@ -94,6 +97,22 @@ void SizeCallback(base::RunLoop* run_loop,
run_loop->Quit();
}
// A blob that never finishes writing to its pipe.
class SlowBlob : public storage::FakeBlob {
public:
explicit SlowBlob(base::OnceClosure quit_closure)
: FakeBlob("foo"), quit_closure_(std::move(quit_closure)) {}
void ReadAll(mojo::ScopedDataPipeProducerHandle producer_handle,
blink::mojom::BlobReaderClientPtr client) override {
// Don't respond, forcing the consumer to wait forever.
std::move(quit_closure_).Run();
}
private:
base::OnceClosure quit_closure_;
};
// A disk_cache::Backend wrapper that can delay operations.
class DelayableBackend : public disk_cache::Backend {
public:
......@@ -416,15 +435,14 @@ class CacheStorageCacheTest : public testing::Test {
blob_storage_context_ = blob_storage_context->context();
const bool is_incognito = MemoryOnly();
base::FilePath temp_dir_path;
if (!is_incognito) {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
temp_dir_path = temp_dir_.GetPath();
temp_dir_path_ = temp_dir_.GetPath();
}
quota_policy_ = new MockSpecialStoragePolicy;
mock_quota_manager_ = new MockQuotaManager(
is_incognito, temp_dir_path, base::ThreadTaskRunnerHandle::Get().get(),
is_incognito, temp_dir_path_, base::ThreadTaskRunnerHandle::Get().get(),
quota_policy_.get());
mock_quota_manager_->SetQuota(
kOrigin, blink::mojom::StorageType::kTemporary, 1024 * 1024 * 100);
......@@ -456,13 +474,13 @@ class CacheStorageCacheTest : public testing::Test {
// CacheStorageCacheHandle reference counting. A LegacyCacheStorage
// must be present to be notified when a cache becomes unreferenced.
mock_cache_storage_ = std::make_unique<MockLegacyCacheStorage>(
temp_dir_path, MemoryOnly(), base::ThreadTaskRunnerHandle::Get().get(),
temp_dir_path_, MemoryOnly(), base::ThreadTaskRunnerHandle::Get().get(),
quota_manager_proxy_, blob_storage_context_->AsWeakPtr(),
/* cache_storage_manager = */ nullptr, kOrigin,
CacheStorageOwner::kCacheAPI);
cache_ = std::make_unique<TestCacheStorageCache>(
kOrigin, kCacheName, temp_dir_path, mock_cache_storage_.get(),
kOrigin, kCacheName, temp_dir_path_, mock_cache_storage_.get(),
quota_manager_proxy_, blob_storage_context->context()->AsWeakPtr());
cache_->Init();
}
......@@ -842,6 +860,7 @@ class CacheStorageCacheTest : public testing::Test {
storage::BlobStorageContext* blob_storage_context_;
std::unique_ptr<MockLegacyCacheStorage> mock_cache_storage_;
base::FilePath temp_dir_path_;
std::unique_ptr<TestCacheStorageCache> cache_;
blink::mojom::FetchAPIRequestPtr body_request_;
......@@ -2211,6 +2230,53 @@ TEST_P(CacheStorageCacheTestP, OpsFailOnClosedBackend) {
VerifyAllOpsFail();
}
// Shutdown the cache in the middle of its writing the response body. Upon
// restarting, that response shouldn't be available. See crbug.com/617683.
TEST_P(CacheStorageCacheTestP, UnfinishedPutsShouldNotBeReusable) {
// Create a response with a blob that takes forever to write its bytes to the
// mojo pipe. Guaranteeing that the response isn't finished writing by the
// time we close the backend.
base::RunLoop run_loop;
auto blob = blink::mojom::SerializedBlob::New();
blob->uuid = "mock blob";
blob->size = 100;
mojo::MakeStrongBinding(std::make_unique<SlowBlob>(run_loop.QuitClosure()),
MakeRequest(&blob->blob));
blink::mojom::FetchAPIResponsePtr response = CreateNoBodyResponse();
response->url_list = {kBodyUrl};
response->blob = std::move(blob);
blink::mojom::BatchOperationPtr operation =
blink::mojom::BatchOperation::New();
operation->operation_type = blink::mojom::OperationType::kPut;
operation->request = BackgroundFetchSettledFetch::CloneRequest(body_request_);
operation->response = std::move(response);
std::vector<blink::mojom::BatchOperationPtr> operations;
operations.emplace_back(std::move(operation));
// Start the put operation and let it run until the blob is supposed to write
// to its pipe.
cache_->BatchOperation(std::move(operations), /* trace_id = */ 0,
base::DoNothing(), base::DoNothing());
run_loop.Run();
// Shut down the cache. Doing so causes the write to cease, and the entry
// should be erased.
cache_ = nullptr;
base::RunLoop().RunUntilIdle();
// Create a new Cache in the same space.
ChromeBlobStorageContext* blob_storage_context =
ChromeBlobStorageContext::GetFor(&browser_context_);
cache_ = std::make_unique<TestCacheStorageCache>(
kOrigin, kCacheName, temp_dir_path_, nullptr /* CacheStorage */,
quota_manager_proxy_, blob_storage_context->context()->AsWeakPtr());
cache_->Init();
// Now attempt to read the same response from the cache. It should fail.
EXPECT_FALSE(Match(body_request_));
}
TEST_P(CacheStorageCacheTestP, BlobReferenceDelaysClose) {
// Create the backend and put something in it.
EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
......
......@@ -39,6 +39,7 @@
#include "content/browser/cache_storage/cache_storage_quota_client.h"
#include "content/browser/cache_storage/cache_storage_scheduler.h"
#include "content/browser/cache_storage/cache_storage_trace_utils.h"
#include "content/browser/cache_storage/legacy/legacy_cache_storage.h"
#include "content/common/background_fetch/background_fetch_types.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/browser_thread.h"
......@@ -1416,7 +1417,11 @@ void LegacyCacheStorageCache::WriteSideDataDidOpenEntry(
std::move(callback).Run(CacheStorageError::kErrorNotFound);
return;
}
disk_cache::ScopedEntryPtr entry(*entry_ptr);
// Moving the entry into a ScopedWritableEntry which will doom the entry
// before closing unless we tell it that writing has successfully completed
// via WritingCompleted.
ScopedWritableEntry entry(*entry_ptr);
ReadMetadata(
*entry_ptr,
......@@ -1432,7 +1437,7 @@ void LegacyCacheStorageCache::WriteSideDataDidReadMetaData(
int64_t trace_id,
scoped_refptr<net::IOBuffer> buffer,
int buf_len,
disk_cache::ScopedEntryPtr entry,
ScopedWritableEntry entry,
std::unique_ptr<proto::CacheMetadata> headers) {
TRACE_EVENT_WITH_FLOW0(
"CacheStorage", "LegacyCacheStorageCache::WriteSideDataDidReadMetaData",
......@@ -1440,7 +1445,8 @@ void LegacyCacheStorageCache::WriteSideDataDidReadMetaData(
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (!headers || headers->response().response_time() !=
expected_response_time.ToInternalValue()) {
std::move(callback).Run(CacheStorageError::kErrorNotFound);
WriteSideDataComplete(std::move(callback), std::move(entry),
CacheStorageError::kErrorNotFound);
return;
}
// Get a temporary copy of the entry pointer before passing it in base::Bind.
......@@ -1472,7 +1478,7 @@ void LegacyCacheStorageCache::WriteSideDataDidReadMetaData(
void LegacyCacheStorageCache::WriteSideDataDidWrite(
ErrorCallback callback,
disk_cache::ScopedEntryPtr entry,
ScopedWritableEntry entry,
int expected_bytes,
std::unique_ptr<::content::proto::CacheResponse> response,
int side_data_size_before_write,
......@@ -1482,9 +1488,8 @@ void LegacyCacheStorageCache::WriteSideDataDidWrite(
"LegacyCacheStorageCache::WriteSideDataDidWrite",
TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN);
if (rv != expected_bytes) {
entry->Doom();
UpdateCacheSize(
base::BindOnce(std::move(callback), CacheStorageError::kErrorNotFound));
WriteSideDataComplete(std::move(callback), std::move(entry),
CacheStorageError::kErrorStorage);
return;
}
......@@ -1499,8 +1504,31 @@ void LegacyCacheStorageCache::WriteSideDataDidWrite(
response.get(), cache_padding_key_.get(), rv);
}
UpdateCacheSize(
base::BindOnce(std::move(callback), CacheStorageError::kSuccess));
WriteSideDataComplete(std::move(callback), std::move(entry),
CacheStorageError::kSuccess);
}
void LegacyCacheStorageCache::WriteSideDataComplete(
ErrorCallback callback,
ScopedWritableEntry entry,
blink::mojom::CacheStorageError error) {
if (error != CacheStorageError::kSuccess) {
// If we found the entry, then we possibly wrote something and now we're
// dooming the entry, causing a change in size, so update the size before
// returning.
if (error != CacheStorageError::kErrorNotFound) {
UpdateCacheSize(base::BindOnce(std::move(callback), error));
return;
}
entry.get_deleter()
.WritingCompleted(); // Since we didn't change the entry.
std::move(callback).Run(error);
return;
}
entry.get_deleter().WritingCompleted(); // Since we didn't change the entry.
UpdateCacheSize(base::BindOnce(std::move(callback), error));
}
void LegacyCacheStorageCache::Put(blink::mojom::BatchOperationPtr operation,
......@@ -1541,8 +1569,8 @@ void LegacyCacheStorageCache::PutImpl(std::unique_ptr<PutContext> put_context) {
CacheStorageTracedValue(put_context->request), "response",
CacheStorageTracedValue(put_context->response));
if (backend_state_ != BACKEND_OPEN) {
std::move(put_context->callback)
.Run(MakeErrorStorage(ErrorStorageType::kPutImplBackendClosed));
PutComplete(std::move(put_context),
MakeErrorStorage(ErrorStorageType::kPutImplBackendClosed));
return;
}
......@@ -1581,15 +1609,15 @@ void LegacyCacheStorageCache::PutDidDeleteEntry(
TRACE_ID_GLOBAL(put_context->trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (backend_state_ != BACKEND_OPEN) {
std::move(put_context->callback)
.Run(MakeErrorStorage(
ErrorStorageType::kPutDidDeleteEntryBackendClosed));
PutComplete(
std::move(put_context),
MakeErrorStorage(ErrorStorageType::kPutDidDeleteEntryBackendClosed));
return;
}
if (error != CacheStorageError::kSuccess &&
error != CacheStorageError::kErrorNotFound) {
std::move(put_context->callback).Run(error);
PutComplete(std::move(put_context), error);
return;
}
......@@ -1624,10 +1652,13 @@ void LegacyCacheStorageCache::PutDidCreateEntry(
TRACE_ID_GLOBAL(put_context->trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
// Moving the entry into a ScopedWritableEntry which will doom the entry
// before closing unless we tell it that writing has successfully completed
// via WritingCompleted.
put_context->cache_entry.reset(*entry_ptr);
if (rv != net::OK) {
std::move(put_context->callback).Run(CacheStorageError::kErrorExists);
PutComplete(std::move(put_context), CacheStorageError::kErrorExists);
return;
}
......@@ -1666,8 +1697,9 @@ void LegacyCacheStorageCache::PutDidCreateEntry(
std::unique_ptr<std::string> serialized(new std::string());
if (!metadata.SerializeToString(serialized.get())) {
std::move(put_context->callback)
.Run(MakeErrorStorage(ErrorStorageType::kMetadataSerializationFailed));
PutComplete(
std::move(put_context),
MakeErrorStorage(ErrorStorageType::kMetadataSerializationFailed));
return;
}
......@@ -1704,9 +1736,9 @@ void LegacyCacheStorageCache::PutDidWriteHeaders(
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (rv != expected_bytes) {
put_context->cache_entry->Doom();
std::move(put_context->callback)
.Run(MakeErrorStorage(ErrorStorageType::kPutDidWriteHeadersWrongBytes));
PutComplete(
std::move(put_context),
MakeErrorStorage(ErrorStorageType::kPutDidWriteHeadersWrongBytes));
return;
}
......@@ -1732,8 +1764,7 @@ void LegacyCacheStorageCache::PutDidWriteHeaders(
return;
}
UpdateCacheSize(base::BindOnce(std::move(put_context->callback),
CacheStorageError::kSuccess));
PutComplete(std::move(put_context), CacheStorageError::kSuccess);
}
void LegacyCacheStorageCache::PutWriteBlobToCache(
......@@ -1747,17 +1778,28 @@ void LegacyCacheStorageCache::PutWriteBlobToCache(
TRACE_ID_GLOBAL(put_context->trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
blink::mojom::BlobPtr blob = disk_cache_body_index == INDEX_RESPONSE_BODY
? std::move(put_context->blob)
: std::move(put_context->side_data_blob);
DCHECK(blob);
blink::mojom::BlobPtr blob;
int64_t blob_size = 0;
int64_t blob_size = disk_cache_body_index == INDEX_RESPONSE_BODY
? put_context->blob_size
: put_context->side_data_blob_size;
switch (disk_cache_body_index) {
case INDEX_RESPONSE_BODY: {
blob = std::move(put_context->blob);
put_context->blob.reset();
blob_size = put_context->blob_size;
break;
}
case INDEX_SIDE_DATA: {
blob = std::move(put_context->side_data_blob);
put_context->side_data_blob.reset();
blob_size = put_context->side_data_blob_size;
break;
}
case INDEX_HEADERS:
NOTREACHED();
}
DCHECK(blob);
disk_cache::ScopedEntryPtr entry(std::move(put_context->cache_entry));
put_context->cache_entry = nullptr;
ScopedWritableEntry entry(put_context->cache_entry.release());
auto blob_to_cache = std::make_unique<CacheStorageBlobToDiskCache>();
CacheStorageBlobToDiskCache* blob_to_cache_raw = blob_to_cache.get();
......@@ -1774,7 +1816,7 @@ void LegacyCacheStorageCache::PutWriteBlobToCache(
void LegacyCacheStorageCache::PutDidWriteBlobToCache(
std::unique_ptr<PutContext> put_context,
BlobToDiskCacheIDMap::KeyType blob_to_cache_key,
disk_cache::ScopedEntryPtr entry,
ScopedWritableEntry entry,
bool success) {
DCHECK(entry);
TRACE_EVENT_WITH_FLOW0("CacheStorage",
......@@ -1787,9 +1829,9 @@ void LegacyCacheStorageCache::PutDidWriteBlobToCache(
active_blob_to_disk_cache_writers_.Remove(blob_to_cache_key);
if (!success) {
put_context->cache_entry->Doom();
std::move(put_context->callback)
.Run(MakeErrorStorage(ErrorStorageType::kPutDidWriteBlobToCacheFailed));
PutComplete(
std::move(put_context),
MakeErrorStorage(ErrorStorageType::kPutDidWriteBlobToCacheFailed));
return;
}
......@@ -1798,8 +1840,24 @@ void LegacyCacheStorageCache::PutDidWriteBlobToCache(
return;
}
UpdateCacheSize(base::BindOnce(std::move(put_context->callback),
CacheStorageError::kSuccess));
PutComplete(std::move(put_context), CacheStorageError::kSuccess);
}
void LegacyCacheStorageCache::PutComplete(
std::unique_ptr<PutContext> put_context,
blink::mojom::CacheStorageError error) {
if (error == CacheStorageError::kSuccess) {
// Make sure we've written everything.
DCHECK(put_context->cache_entry);
DCHECK(!put_context->blob);
DCHECK(!put_context->side_data_blob);
// Tell the WritableScopedEntry not to doom the entry since it was a
// successful operation.
put_context->cache_entry.get_deleter().WritingCompleted();
}
UpdateCacheSize(base::BindOnce(std::move(put_context->callback), error));
}
void LegacyCacheStorageCache::CalculateCacheSizePadding(
......
......@@ -19,6 +19,7 @@
#include "base/optional.h"
#include "content/browser/cache_storage/cache_storage_cache.h"
#include "content/browser/cache_storage/cache_storage_handle.h"
#include "content/browser/cache_storage/scoped_writable_entry.h"
#include "content/common/service_worker/service_worker_types.h"
#include "net/base/completion_once_callback.h"
#include "net/base/io_buffer.h"
......@@ -333,16 +334,19 @@ class CONTENT_EXPORT LegacyCacheStorageCache : public CacheStorageCache {
int64_t trace_id,
scoped_refptr<net::IOBuffer> buffer,
int buf_len,
disk_cache::ScopedEntryPtr entry,
ScopedWritableEntry entry,
std::unique_ptr<proto::CacheMetadata> headers);
void WriteSideDataDidWrite(
ErrorCallback callback,
disk_cache::ScopedEntryPtr entry,
ScopedWritableEntry entry,
int expected_bytes,
std::unique_ptr<content::proto::CacheResponse> response,
int side_data_size_before_write,
int64_t trace_id,
int rv);
void WriteSideDataComplete(ErrorCallback callback,
ScopedWritableEntry entry,
blink::mojom::CacheStorageError error);
// Puts the request and response object in the cache. The response body (if
// present) is stored in the cache, but not the request body. Returns OK on
......@@ -367,8 +371,10 @@ class CONTENT_EXPORT LegacyCacheStorageCache : public CacheStorageCache {
int disk_cache_body_index);
void PutDidWriteBlobToCache(std::unique_ptr<PutContext> put_context,
BlobToDiskCacheIDMap::KeyType blob_to_cache_key,
disk_cache::ScopedEntryPtr entry,
ScopedWritableEntry entry,
bool success);
void PutComplete(std::unique_ptr<PutContext> put_context,
blink::mojom::CacheStorageError error);
// Asynchronously calculates the current cache size, notifies the quota
// manager of any change from the last report, and sets cache_size_ to the new
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_CACHE_STORAGE_SCOPED_WRITABLE_ENTRY_H_
#define CONTENT_BROWSER_CACHE_STORAGE_SCOPED_WRITABLE_ENTRY_H_
#include <memory>
#include "net/disk_cache/disk_cache.h"
namespace content {
// A custom deleter that closes the entry. But if WritingCompleted() hasn't been
// called, it will doom the entry before closing it.
class ScopedWritableDeleter {
public:
ScopedWritableDeleter() = default;
ScopedWritableDeleter(ScopedWritableDeleter&& other) = default;
ScopedWritableDeleter& operator=(ScopedWritableDeleter&& other) = default;
void operator()(disk_cache::Entry* entry) {
if (!completed_)
entry->Doom();
// |entry| is owned by the backend, we just need to close it as it's
// ref-counted.
entry->Close();
}
void WritingCompleted() { completed_ = true; }
private:
bool completed_ = false;
};
// Use this to manage disk_cache::Entry*'s that should be doomed before closing
// unless told otherwise (via calling WritingCompleted on the deleter).
//
// Example:
// ScopedWritableEntry entry(my_entry);
// .. write some stuff ..
// entry.get_deleter().WritingCompleted();
typedef std::unique_ptr<disk_cache::Entry, ScopedWritableDeleter>
ScopedWritableEntry;
} // namespace content
#endif // CONTENT_BROWSER_CACHE_STORAGE_SCOPED_WRITABLE_ENTRY_H_
......@@ -480,6 +480,9 @@ struct EntryDeleter {
};
// Automatically closes an entry when it goes out of scope.
// Warning: Be careful. Automatically closing may not be the desired behavior
// when writing to an entry. You may wish to doom first (e.g., in case writing
// hasn't yet completed but the browser is shutting down).
typedef std::unique_ptr<Entry, EntryDeleter> ScopedEntryPtr;
} // namespace disk_cache
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment