Commit 21a6dd4b authored by Rayan Kanso's avatar Rayan Kanso Committed by Commit Bot

[Background Fetch] Create a cache entry handler for BGF.

The handler uses the side data blob to store the request body if any.

Bug: 774054
Change-Id: I14ec3e992543937bef7a601bcb603103842c6acf
Reviewed-on: https://chromium-review.googlesource.com/c/1363205
Commit-Queue: Rayan Kanso <rayankans@chromium.org>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Reviewed-by: default avatarBen Kelly <wanderview@chromium.org>
Reviewed-by: default avatarMugdha Lakhani <nator@chromium.org>
Cr-Commit-Position: refs/heads/master@{#615515}
parent 79782f30
......@@ -440,6 +440,8 @@ jumbo_source_set("browser") {
"background_fetch/background_fetch_scheduler.h",
"background_fetch/background_fetch_service_impl.cc",
"background_fetch/background_fetch_service_impl.h",
"background_fetch/storage/cache_entry_handler_impl.cc",
"background_fetch/storage/cache_entry_handler_impl.h",
"background_fetch/storage/cleanup_task.cc",
"background_fetch/storage/cleanup_task.h",
"background_fetch/storage/create_metadata_task.cc",
......
......@@ -35,9 +35,11 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/test_utils.h"
#include "mojo/public/cpp/system/data_pipe_drainer.h"
#include "services/network/public/mojom/fetch_api.mojom.h"
#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/blob/blob_impl.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom.h"
......@@ -716,6 +718,32 @@ class BackgroundFetchDataManagerTest
std::move(quit_closure).Run();
}
class DataPipeDrainerClient : public mojo::DataPipeDrainer::Client {
public:
explicit DataPipeDrainerClient(std::string* output) : output_(output) {}
void Run() { run_loop_.Run(); }
void OnDataAvailable(const void* data, size_t num_bytes) override {
output_->append(reinterpret_cast<const char*>(data), num_bytes);
}
void OnDataComplete() override { run_loop_.Quit(); }
private:
base::RunLoop run_loop_;
std::string* output_;
};
std::string CopyBody(blink::mojom::Blob* blob) {
mojo::DataPipe pipe;
blob->ReadAll(std::move(pipe.producer_handle), /* client= */ nullptr);
std::string output;
DataPipeDrainerClient client(&output);
mojo::DataPipeDrainer drainer(&client, std::move(pipe.consumer_handle));
client.Run();
return output;
}
blink::mojom::SerializedBlobPtr BuildBlob(const std::string data) {
auto blob_data = std::make_unique<storage::BlobDataBuilder>(
"blob-id:" + base::GenerateGUID());
......@@ -727,6 +755,9 @@ class BackgroundFetchDataManagerTest
auto blob = blink::mojom::SerializedBlob::New();
blob->uuid = blob_handle->uuid();
blob->size = blob_handle->size();
storage::BlobImpl::Create(
std::make_unique<storage::BlobDataHandle>(*blob_handle),
MakeRequest(&blob->blob));
return blob;
}
......@@ -1616,6 +1647,45 @@ TEST_F(BackgroundFetchDataManagerTest, MatchRequests) {
EXPECT_EQ(settled_fetches.size(), num_requests);
}
TEST_F(BackgroundFetchDataManagerTest, MatchRequestsWithBody) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
std::vector<blink::mojom::FetchAPIRequestPtr> requests =
CreateValidRequests(origin(), 2u);
const std::string upload_data = "Upload data!";
requests[1]->blob = BuildBlob(upload_data);
auto options = blink::mojom::BackgroundFetchOptions::New();
blink::mojom::BackgroundFetchError error;
BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
{
EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _, _));
CreateRegistration(registration_id, std::move(requests), std::move(options),
SkBitmap(), &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
}
std::vector<BackgroundFetchSettledFetch> settled_fetches;
MatchRequests(registration_id, /* request_to_match= */ nullptr,
/* cache_query_params= */ nullptr, /* match_all= */ true,
&error, &settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
ASSERT_EQ(settled_fetches.size(), 2u);
EXPECT_FALSE(settled_fetches[0].request->blob);
auto& request = settled_fetches[1].request;
ASSERT_TRUE(request->blob);
EXPECT_EQ(request->blob->size, upload_data.size());
ASSERT_TRUE(request->blob->blob);
blink::mojom::BlobPtr blob(std::move(request->blob->blob));
EXPECT_EQ(CopyBody(blob.get()), upload_data);
}
TEST_F(BackgroundFetchDataManagerTest, MatchRequestsFromCache) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
......
// Copyright 2018 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.
#include "content/browser/background_fetch/storage/cache_entry_handler_impl.h"
#include "base/guid.h"
#include "storage/browser/blob/blob_impl.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "third_party/blink/public/common/blob/blob_utils.h"
namespace content {
namespace background_fetch {
CacheEntryHandlerImpl::CacheEntryHandlerImpl(
base::WeakPtr<storage::BlobStorageContext> blob_context)
: CacheStorageCacheEntryHandler(std::move(blob_context)),
weak_ptr_factory_(this) {}
CacheEntryHandlerImpl::~CacheEntryHandlerImpl() = default;
std::unique_ptr<PutContext> CacheEntryHandlerImpl::CreatePutContext(
blink::mojom::FetchAPIRequestPtr request,
blink::mojom::FetchAPIResponsePtr response) {
blink::mojom::BlobPtr response_blob;
uint64_t response_blob_size = blink::BlobUtils::kUnknownSize;
blink::mojom::BlobPtr request_blob;
uint64_t request_blob_size = blink::BlobUtils::kUnknownSize;
if (response->blob) {
response_blob.Bind(std::move(response->blob->blob));
response_blob_size = response->blob->size;
}
if (request->blob) {
request_blob.Bind(std::move(request->blob->blob));
request_blob_size = request->blob->size;
}
return std::make_unique<PutContext>(
std::move(request), std::move(response), std::move(response_blob),
response_blob_size, std::move(request_blob), request_blob_size);
}
void CacheEntryHandlerImpl::PopulateBody(
scoped_refptr<BlobDataHandle> data_handle,
const blink::mojom::SerializedBlobPtr& blob,
CacheStorageCache::EntryIndex index) {
disk_cache::Entry* entry = data_handle->entry().get();
DCHECK(entry);
blob->size = entry->GetDataSize(index);
blob->uuid = base::GenerateGUID();
auto blob_data = std::make_unique<storage::BlobDataBuilder>(blob->uuid);
blob_data->AppendDiskCacheEntry(std::move(data_handle), entry, index);
auto blob_handle = blob_context_->AddFinishedBlob(std::move(blob_data));
storage::BlobImpl::Create(std::move(blob_handle), MakeRequest(&blob->blob));
}
void CacheEntryHandlerImpl::PopulateResponseBody(
scoped_refptr<BlobDataHandle> data_handle,
blink::mojom::FetchAPIResponse* response) {
response->blob = blink::mojom::SerializedBlob::New();
PopulateBody(std::move(data_handle), response->blob,
CacheStorageCache::INDEX_RESPONSE_BODY);
}
void CacheEntryHandlerImpl::PopulateRequestBody(
scoped_refptr<BlobDataHandle> data_handle,
blink::mojom::FetchAPIRequest* request) {
if (!data_handle->entry() ||
!data_handle->entry()->GetDataSize(CacheStorageCache::INDEX_SIDE_DATA)) {
return;
}
request->blob = blink::mojom::SerializedBlob::New();
PopulateBody(std::move(data_handle), request->blob,
CacheStorageCache::INDEX_SIDE_DATA);
}
base::WeakPtr<CacheStorageCacheEntryHandler>
CacheEntryHandlerImpl::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
} // namespace background_fetch
} // namespace content
\ No newline at end of file
// Copyright 2018 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_BACKGROUND_FETCH_STORAGE_CACHE_ENTRY_HANDLER_IMPL_H_
#define CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_CACHE_ENTRY_HANDLER_IMPL_H_
#include "content/browser/cache_storage/cache_storage_cache_entry_handler.h"
#include "content/browser/cache_storage/cache_storage_cache.h"
namespace content {
namespace background_fetch {
class CacheEntryHandlerImpl : public CacheStorageCacheEntryHandler {
public:
explicit CacheEntryHandlerImpl(
base::WeakPtr<storage::BlobStorageContext> blob_context);
~CacheEntryHandlerImpl() override;
// CacheStorageCacheEntryHandler implementation:
std::unique_ptr<PutContext> CreatePutContext(
blink::mojom::FetchAPIRequestPtr request,
blink::mojom::FetchAPIResponsePtr response) override;
void PopulateResponseBody(scoped_refptr<BlobDataHandle> data_handle,
blink::mojom::FetchAPIResponse* response) override;
void PopulateRequestBody(scoped_refptr<BlobDataHandle> data_handle,
blink::mojom::FetchAPIRequest* request) override;
private:
void PopulateBody(scoped_refptr<BlobDataHandle> data_handle,
const blink::mojom::SerializedBlobPtr& blob,
CacheStorageCache::EntryIndex index);
base::WeakPtr<CacheStorageCacheEntryHandler> GetWeakPtr() override;
base::WeakPtrFactory<CacheEntryHandlerImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CacheEntryHandlerImpl);
};
} // namespace background_fetch
} // namespace content
#endif // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_CACHE_ENTRY_HANDLER_IMPL_H_
......@@ -190,8 +190,8 @@ void MarkRequestCompleteTask::DidOpenCache(
blink::mojom::FetchAPIRequestPtr request =
BackgroundFetchSettledFetch::CloneRequest(request_info_->fetch_request());
// We need to keep the handle refcounted while the write is happening,
// so it's passed along to the callback.
// TODO(crbug.com/774054): The request blob stored in the cache is being
// overwritten here, it should be written back.
handle.value()->Put(
std::move(request), std::move(response),
base::BindOnce(&MarkRequestCompleteTask::DidWriteToCache,
......
......@@ -1119,8 +1119,11 @@ void CacheStorageCache::QueryCacheDidReadMetadata(
return;
}
auto data_handle = cache_entry_handler_->CreateBlobDataHandle(
CreateHandle(), std::move(entry));
if (query_cache_context->query_types & QUERY_CACHE_ENTRIES)
match->entry = std::move(entry);
match->entry = std::move(data_handle->entry());
if (query_cache_context->query_types & QUERY_CACHE_REQUESTS) {
query_cache_context->estimated_out_bytes +=
......@@ -1130,6 +1133,9 @@ void CacheStorageCache::QueryCacheDidReadMetadata(
.Run(CacheStorageError::kErrorQueryTooLarge, nullptr);
return;
}
cache_entry_handler_->PopulateRequestBody(data_handle,
match->request.get());
} else {
match->request.reset();
}
......@@ -1142,7 +1148,7 @@ void CacheStorageCache::QueryCacheDidReadMetadata(
.Run(CacheStorageError::kErrorQueryTooLarge, nullptr);
return;
}
if (entry->GetDataSize(INDEX_RESPONSE_BODY) == 0) {
if (data_handle->entry()->GetDataSize(INDEX_RESPONSE_BODY) == 0) {
QueryCacheOpenNextEntry(std::move(query_cache_context));
return;
}
......@@ -1155,7 +1161,7 @@ void CacheStorageCache::QueryCacheDidReadMetadata(
return;
}
cache_entry_handler_->PopulateResponseBody(CreateHandle(), std::move(entry),
cache_entry_handler_->PopulateResponseBody(data_handle,
match->response.get());
} else if (!(query_cache_context->query_types &
QUERY_CACHE_RESPONSES_NO_BODIES)) {
......@@ -1592,13 +1598,20 @@ void CacheStorageCache::PutDidWriteHeaders(
// The metadata is written, now for the response content. The data is streamed
// from the blob into the cache entry.
if (!put_context->response->blob ||
put_context->response->blob->uuid.empty()) {
UpdateCacheSize(base::BindOnce(std::move(put_context->callback),
CacheStorageError::kSuccess));
if (put_context->response->blob &&
!put_context->response->blob->uuid.empty()) {
PutWriteBlobToCache(std::move(put_context), INDEX_RESPONSE_BODY);
return;
}
if (put_context->side_data_blob) {
DCHECK_EQ(owner_, CacheStorageOwner::kBackgroundFetch);
PutWriteBlobToCache(std::move(put_context), INDEX_SIDE_DATA);
return;
}
PutWriteBlobToCache(std::move(put_context), INDEX_RESPONSE_BODY);
UpdateCacheSize(base::BindOnce(std::move(put_context->callback),
CacheStorageError::kSuccess));
}
void CacheStorageCache::PutWriteBlobToCache(
......
......@@ -6,6 +6,7 @@
#include "base/guid.h"
#include "base/optional.h"
#include "content/browser/background_fetch/storage/cache_entry_handler_impl.h"
#include "content/browser/cache_storage/cache_storage_cache.h"
#include "content/browser/cache_storage/cache_storage_manager.h"
#include "storage/browser/blob/blob_data_builder.h"
......@@ -58,7 +59,8 @@ class CacheStorageCacheEntryHandlerImpl : public CacheStorageCacheEntryHandler {
public:
CacheStorageCacheEntryHandlerImpl(
base::WeakPtr<storage::BlobStorageContext> blob_context)
: CacheStorageCacheEntryHandler(std::move(blob_context)) {}
: CacheStorageCacheEntryHandler(std::move(blob_context)),
weak_ptr_factory_(this) {}
~CacheStorageCacheEntryHandlerImpl() override = default;
std::unique_ptr<PutContext> CreatePutContext(
......@@ -83,9 +85,11 @@ class CacheStorageCacheEntryHandlerImpl : public CacheStorageCacheEntryHandler {
std::move(side_data_blob), side_data_blob_size);
}
void PopulateResponseBody(CacheStorageCacheHandle handle,
disk_cache::ScopedEntryPtr entry,
void PopulateResponseBody(scoped_refptr<BlobDataHandle> data_handle,
blink::mojom::FetchAPIResponse* response) override {
disk_cache::Entry* entry = data_handle->entry().get();
DCHECK(entry);
// Create a blob with the response body data.
response->blob = blink::mojom::SerializedBlob::New();
response->blob->size =
......@@ -94,15 +98,8 @@ class CacheStorageCacheEntryHandlerImpl : public CacheStorageCacheEntryHandler {
auto blob_data =
std::make_unique<storage::BlobDataBuilder>(response->blob->uuid);
disk_cache::Entry* temp_entry = entry.get();
auto data_handle =
base::MakeRefCounted<CacheStorageCacheEntryHandler::BlobDataHandle>(
weak_ptr_factory_.GetWeakPtr(), std::move(handle),
std::move(entry));
blob_data_handles_.insert(data_handle.get());
blob_data->AppendDiskCacheEntryWithSideData(
std::move(data_handle), temp_entry,
CacheStorageCache::INDEX_RESPONSE_BODY,
std::move(data_handle), entry, CacheStorageCache::INDEX_RESPONSE_BODY,
CacheStorageCache::INDEX_SIDE_DATA);
auto blob_handle = blob_context_->AddFinishedBlob(std::move(blob_data));
......@@ -110,14 +107,32 @@ class CacheStorageCacheEntryHandlerImpl : public CacheStorageCacheEntryHandler {
MakeRequest(&response->blob->blob));
}
void PopulateRequestBody(CacheStorageCacheHandle handle,
disk_cache::ScopedEntryPtr entry,
void PopulateRequestBody(scoped_refptr<BlobDataHandle> data_handle,
blink::mojom::FetchAPIRequest* request) override {}
private:
base::WeakPtr<CacheStorageCacheEntryHandler> GetWeakPtr() override {
return weak_ptr_factory_.GetWeakPtr();
}
base::WeakPtrFactory<CacheStorageCacheEntryHandlerImpl> weak_ptr_factory_;
};
CacheStorageCacheEntryHandler::CacheStorageCacheEntryHandler(
base::WeakPtr<storage::BlobStorageContext> blob_context)
: blob_context_(blob_context), weak_ptr_factory_(this) {}
: blob_context_(blob_context) {}
scoped_refptr<CacheStorageCacheEntryHandler::BlobDataHandle>
CacheStorageCacheEntryHandler::CreateBlobDataHandle(
CacheStorageCacheHandle cache_handle,
disk_cache::ScopedEntryPtr entry) {
auto handle =
base::MakeRefCounted<CacheStorageCacheEntryHandler::BlobDataHandle>(
GetWeakPtr(), std::move(cache_handle), std::move(entry));
DCHECK_EQ(blob_data_handles_.count(handle.get()), 0u);
blob_data_handles_.insert(handle.get());
return handle;
}
CacheStorageCacheEntryHandler::~CacheStorageCacheEntryHandler() = default;
......@@ -140,8 +155,15 @@ std::unique_ptr<CacheStorageCacheEntryHandler>
CacheStorageCacheEntryHandler::CreateCacheEntryHandler(
CacheStorageOwner owner,
base::WeakPtr<storage::BlobStorageContext> blob_context) {
return std::make_unique<CacheStorageCacheEntryHandlerImpl>(
std::move(blob_context));
switch (owner) {
case CacheStorageOwner::kCacheAPI:
return std::make_unique<CacheStorageCacheEntryHandlerImpl>(
std::move(blob_context));
case CacheStorageOwner::kBackgroundFetch:
return std::make_unique<background_fetch::CacheEntryHandlerImpl>(
std::move(blob_context));
}
NOTREACHED();
}
} // namespace content
......@@ -9,6 +9,7 @@
#include <set>
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/cache_storage/cache_storage_cache_handle.h"
#include "content/common/content_export.h"
......@@ -68,6 +69,8 @@ class CONTENT_EXPORT CacheStorageCacheEntryHandler {
void Invalidate();
disk_cache::ScopedEntryPtr& entry() { return entry_; }
private:
~BlobDataHandle() override;
......@@ -78,17 +81,19 @@ class CONTENT_EXPORT CacheStorageCacheEntryHandler {
DISALLOW_COPY_AND_ASSIGN(BlobDataHandle);
};
scoped_refptr<BlobDataHandle> CreateBlobDataHandle(
CacheStorageCacheHandle cache_handle,
disk_cache::ScopedEntryPtr entry);
virtual ~CacheStorageCacheEntryHandler();
virtual std::unique_ptr<PutContext> CreatePutContext(
blink::mojom::FetchAPIRequestPtr request,
blink::mojom::FetchAPIResponsePtr response) = 0;
virtual void PopulateResponseBody(
CacheStorageCacheHandle handle,
disk_cache::ScopedEntryPtr entry,
scoped_refptr<BlobDataHandle> data_handle,
blink::mojom::FetchAPIResponse* response) = 0;
virtual void PopulateRequestBody(CacheStorageCacheHandle handle,
disk_cache::ScopedEntryPtr entry,
virtual void PopulateRequestBody(scoped_refptr<BlobDataHandle> data_handle,
blink::mojom::FetchAPIRequest* request) = 0;
static std::unique_ptr<CacheStorageCacheEntryHandler> CreateCacheEntryHandler(
......@@ -96,7 +101,6 @@ class CONTENT_EXPORT CacheStorageCacheEntryHandler {
base::WeakPtr<storage::BlobStorageContext> blob_context);
void InvalidateBlobDataHandles();
void EraseBlobDataHandle(BlobDataHandle* handle);
protected:
......@@ -105,13 +109,15 @@ class CONTENT_EXPORT CacheStorageCacheEntryHandler {
base::WeakPtr<storage::BlobStorageContext> blob_context_;
// Every subclass should provide its own implementation to avoid partial
// destruction.
virtual base::WeakPtr<CacheStorageCacheEntryHandler> GetWeakPtr() = 0;
// We keep track of the BlobDataHandle instances to allow us to invalidate
// them if the cache has to be deleted while there are still references to
// data in it.
std::set<BlobDataHandle*> blob_data_handles_;
base::WeakPtrFactory<CacheStorageCacheEntryHandler> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CacheStorageCacheEntryHandler);
};
......
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