blob: 7c9f18c8d4ab934b94f08d5af404a64b70c70f5c [file] [log] [blame]
// Copyright 2015 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/cache_storage/cache_storage_dispatcher_host.h"
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
#include "content/browser/cache_storage/cache_storage.h"
#include "content/browser/cache_storage/cache_storage_cache.h"
#include "content/browser/cache_storage/cache_storage_context_impl.h"
#include "content/browser/cache_storage/cache_storage_histogram_utils.h"
#include "content/browser/cache_storage/cache_storage_manager.h"
#include "content/browser/cache_storage/cache_storage_trace_utils.h"
#include "content/common/background_fetch/background_fetch_types.h"
#include "content/public/common/content_features.h"
#include "content/public/common/origin_util.h"
#include "content/public/common/referrer_type_converters.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "third_party/blink/public/common/blob/blob_utils.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
namespace {
using blink::mojom::CacheStorageError;
using blink::mojom::CacheStorageVerboseError;
// TODO(lucmult): Check this before binding.
bool OriginCanAccessCacheStorage(const url::Origin& origin) {
return !origin.opaque() && IsOriginSecure(origin.GetURL());
}
// Verifies that the BatchOperation list conforms to the constraints imposed
// by the web exposed Cache API. Don't permit compromised renderers to use
// unexpected operation combinations.
bool ValidBatchOperations(
const std::vector<blink::mojom::BatchOperationPtr>& batch_operations) {
// At least one operation is required.
if (batch_operations.empty())
return false;
blink::mojom::OperationType type = batch_operations[0]->operation_type;
// We must have a defined operation type. All other enum values allowed
// by the mojo validator are permitted here.
if (type == blink::mojom::OperationType::kUndefined)
return false;
// Delete operations should only be sent one at a time.
if (type == blink::mojom::OperationType::kDelete &&
batch_operations.size() > 1) {
return false;
}
// All operations in the list must be the same.
for (const auto& op : batch_operations) {
if (op->operation_type != type)
return false;
}
return true;
}
blink::mojom::MatchResultPtr EagerlyReadResponseBody(
blink::mojom::FetchAPIResponsePtr response) {
if (!response->blob ||
!base::FeatureList::IsEnabled(features::kCacheStorageEagerReading)) {
return blink::mojom::MatchResult::NewResponse(std::move(response));
}
MojoCreateDataPipeOptions options;
options.struct_size = sizeof(MojoCreateDataPipeOptions);
options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
options.element_num_bytes = 1;
options.capacity_num_bytes =
blink::BlobUtils::GetDataPipeCapacity(response->blob->size);
mojo::ScopedDataPipeProducerHandle producer_handle;
mojo::ScopedDataPipeConsumerHandle consumer_handle;
MojoResult rv = CreateDataPipe(&options, &producer_handle, &consumer_handle);
if (rv != MOJO_RESULT_OK)
return blink::mojom::MatchResult::NewResponse(std::move(response));
mojo::PendingRemote<blink::mojom::BlobReaderClient> reader_client;
auto pending_receiver = reader_client.InitWithNewPipeAndPassReceiver();
mojo::Remote<blink::mojom::Blob> blob(std::move(response->blob->blob));
blob->ReadAll(std::move(producer_handle), std::move(reader_client));
// Clear the main body blob entry. There should still be a |side_data_blob|
// value for reading code cache, however.
response->blob = nullptr;
DCHECK(response->side_data_blob);
return blink::mojom::MatchResult::NewEagerResponse(
blink::mojom::EagerResponse::New(std::move(response),
std::move(consumer_handle),
std::move(pending_receiver)));
}
} // namespace
// Implements the mojom interface CacheStorageCache. It's owned by
// CacheStorageDispatcherHost and it's destroyed when client drops the mojo ptr
// which in turn removes from StrongBindingSet in CacheStorageDispatcherHost.
class CacheStorageDispatcherHost::CacheImpl
: public blink::mojom::CacheStorageCache {
public:
explicit CacheImpl(CacheStorageCacheHandle cache_handle)
: cache_handle_(std::move(cache_handle)) {}
~CacheImpl() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); }
// blink::mojom::CacheStorageCache implementation:
void Match(blink::mojom::FetchAPIRequestPtr request,
blink::mojom::CacheQueryOptionsPtr match_options,
bool in_related_fetch_event,
int64_t trace_id,
MatchCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
TRACE_EVENT_WITH_FLOW2("CacheStorage",
"CacheStorageDispatchHost::CacheImpl::Match",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"request", CacheStorageTracedValue(request),
"options", CacheStorageTracedValue(match_options));
content::CacheStorageCache* cache = cache_handle_.value();
bool cache_initialized =
cache ? cache->GetInitState() ==
content::CacheStorageCache::InitState::Initialized
: false;
auto cb = base::BindOnce(
[](base::TimeTicks start_time, bool ignore_search,
bool in_related_fetch_event, bool cache_initialized,
int64_t trace_id,
blink::mojom::CacheStorageCache::MatchCallback callback,
blink::mojom::CacheStorageError error,
blink::mojom::FetchAPIResponsePtr response) {
base::TimeDelta elapsed = base::TimeTicks::Now() - start_time;
UMA_HISTOGRAM_LONG_TIMES("ServiceWorkerCache.Cache.Browser.Match",
elapsed);
if (ignore_search) {
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.Cache.Browser.Match.IgnoreSearch", elapsed);
}
if (cache_initialized) {
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.Cache.Browser.Match.Initialized", elapsed);
}
if (error == CacheStorageError::kErrorNotFound) {
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.Cache.Browser.Match.Miss", elapsed);
}
if (error != CacheStorageError::kSuccess) {
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheImpl::Match::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "status",
CacheStorageTracedValue(error));
std::move(callback).Run(
blink::mojom::MatchResult::NewStatus(error));
return;
}
UMA_HISTOGRAM_LONG_TIMES("ServiceWorkerCache.Cache.Browser.Match.Hit",
elapsed);
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheImpl::Match::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "response",
CacheStorageTracedValue(response));
blink::mojom::MatchResultPtr result;
if (in_related_fetch_event) {
result = EagerlyReadResponseBody(std::move(response));
} else {
result =
blink::mojom::MatchResult::NewResponse(std::move(response));
}
std::move(callback).Run(std::move(result));
},
base::TimeTicks::Now(), match_options->ignore_search,
in_related_fetch_event, cache_initialized, trace_id,
std::move(callback));
if (!cache) {
std::move(cb).Run(CacheStorageError::kErrorNotFound, nullptr);
return;
}
cache->Match(std::move(request), std::move(match_options), trace_id,
std::move(cb));
}
void MatchAll(blink::mojom::FetchAPIRequestPtr request,
blink::mojom::CacheQueryOptionsPtr match_options,
int64_t trace_id,
MatchAllCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
TRACE_EVENT_WITH_FLOW2("CacheStorage",
"CacheStorageDispatchHost::CacheImpl::MatchAll",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"request", CacheStorageTracedValue(request),
"options", CacheStorageTracedValue(match_options));
auto cb = base::BindOnce(
[](base::TimeTicks start_time, int64_t trace_id,
blink::mojom::CacheStorageCache::MatchAllCallback callback,
blink::mojom::CacheStorageError error,
std::vector<blink::mojom::FetchAPIResponsePtr> responses) {
base::TimeDelta elapsed = base::TimeTicks::Now() - start_time;
UMA_HISTOGRAM_LONG_TIMES("ServiceWorkerCache.Cache.Browser.MatchAll",
elapsed);
if (error != CacheStorageError::kSuccess &&
error != CacheStorageError::kErrorNotFound) {
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheImpl::MatchAll::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "status",
CacheStorageTracedValue(error));
std::move(callback).Run(
blink::mojom::MatchAllResult::NewStatus(error));
return;
}
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheImpl::MatchAll::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"response_list", CacheStorageTracedValue(responses));
std::move(callback).Run(
blink::mojom::MatchAllResult::NewResponses(std::move(responses)));
},
base::TimeTicks::Now(), trace_id, std::move(callback));
content::CacheStorageCache* cache = cache_handle_.value();
if (!cache) {
std::move(cb).Run(CacheStorageError::kErrorNotFound,
std::vector<blink::mojom::FetchAPIResponsePtr>());
return;
}
cache->MatchAll(std::move(request), std::move(match_options), trace_id,
std::move(cb));
}
void Keys(blink::mojom::FetchAPIRequestPtr request,
blink::mojom::CacheQueryOptionsPtr match_options,
int64_t trace_id,
KeysCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
TRACE_EVENT_WITH_FLOW2("CacheStorage",
"CacheStorageDispatchHost::CacheImpl::Keys",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"request", CacheStorageTracedValue(request),
"options", CacheStorageTracedValue(match_options));
auto cb = base::BindOnce(
[](base::TimeTicks start_time, int64_t trace_id,
blink::mojom::CacheStorageCache::KeysCallback callback,
blink::mojom::CacheStorageError error,
std::unique_ptr<content::CacheStorageCache::Requests> requests) {
UMA_HISTOGRAM_LONG_TIMES("ServiceWorkerCache.Cache.Browser.Keys",
base::TimeTicks::Now() - start_time);
if (error != CacheStorageError::kSuccess) {
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheImpl::Keys::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "status",
CacheStorageTracedValue(error));
std::move(callback).Run(
blink::mojom::CacheKeysResult::NewStatus(error));
return;
}
std::vector<blink::mojom::FetchAPIRequestPtr> requests_;
for (const auto& request : *requests) {
requests_.push_back(
BackgroundFetchSettledFetch::CloneRequest(request));
}
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheImpl::Keys::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"request_list", CacheStorageTracedValue(requests_));
std::move(callback).Run(
blink::mojom::CacheKeysResult::NewKeys(std::move(requests_)));
},
base::TimeTicks::Now(), trace_id, std::move(callback));
content::CacheStorageCache* cache = cache_handle_.value();
if (!cache) {
std::move(cb).Run(CacheStorageError::kErrorNotFound, nullptr);
return;
}
cache->Keys(std::move(request), std::move(match_options), trace_id,
std::move(cb));
}
void Batch(std::vector<blink::mojom::BatchOperationPtr> batch_operations,
int64_t trace_id,
BatchCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
TRACE_EVENT_WITH_FLOW1(
"CacheStorage", "CacheStorageDispatchHost::CacheImpl::Batch",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "operation_list",
CacheStorageTracedValue(batch_operations));
if (!ValidBatchOperations(batch_operations)) {
mojo::ReportBadMessage("CSDH_UNEXPECTED_OPERATION");
return;
}
// Validated batch operations always have at least one entry.
blink::mojom::OperationType operation_type =
batch_operations[0]->operation_type;
int operation_count = batch_operations.size();
auto cb = base::BindOnce(
[](base::TimeTicks start_time,
blink::mojom::OperationType operation_type, int operation_count,
int64_t trace_id,
blink::mojom::CacheStorageCache::BatchCallback callback,
blink::mojom::CacheStorageVerboseErrorPtr error) {
base::TimeDelta elapsed = base::TimeTicks::Now() - start_time;
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheImpl::Batch::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "status",
CacheStorageTracedValue(error->value));
if (operation_type == blink::mojom::OperationType::kDelete) {
DCHECK_EQ(operation_count, 1);
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.Cache.Browser.DeleteOne", elapsed);
} else if (operation_count > 1) {
DCHECK_EQ(operation_type, blink::mojom::OperationType::kPut);
UMA_HISTOGRAM_LONG_TIMES("ServiceWorkerCache.Cache.Browser.PutMany",
elapsed);
} else {
DCHECK_EQ(operation_type, blink::mojom::OperationType::kPut);
UMA_HISTOGRAM_LONG_TIMES("ServiceWorkerCache.Cache.Browser.PutOne",
elapsed);
}
std::move(callback).Run(std::move(error));
},
base::TimeTicks::Now(), operation_type, operation_count, trace_id,
std::move(callback));
content::CacheStorageCache* cache = cache_handle_.value();
if (!cache) {
std::move(cb).Run(CacheStorageVerboseError::New(
CacheStorageError::kErrorNotFound, base::nullopt));
return;
}
cache->BatchOperation(
std::move(batch_operations), trace_id, std::move(cb),
base::BindOnce(
[](mojo::ReportBadMessageCallback bad_message_callback) {
std::move(bad_message_callback).Run("CSDH_UNEXPECTED_OPERATION");
},
mojo::GetBadMessageCallback()));
}
CacheStorageCacheHandle cache_handle_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(CacheImpl);
};
// Implements the mojom interface CacheStorage. It's owned by the
// CacheStorageDispatcherHost. The CacheStorageImpl is destroyed when the
// client drops its mojo ptr which in turn removes from StrongBindingSet in
// CacheStorageDispatcherHost.
class CacheStorageDispatcherHost::CacheStorageImpl final
: public blink::mojom::CacheStorage {
public:
CacheStorageImpl(CacheStorageDispatcherHost* owner, const url::Origin& origin)
: owner_(owner), origin_(origin) {
// The CacheStorageHandle is empty to start and lazy initialized on first
// use via GetOrCreateCacheStorage(). In the future we could eagerly create
// the backend when the mojo connection is created.
}
~CacheStorageImpl() override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
// Mojo CacheStorage Interface implementation:
void Keys(int64_t trace_id,
blink::mojom::CacheStorage::KeysCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
TRACE_EVENT_WITH_FLOW0(
"CacheStorage", "CacheStorageDispatchHost::CacheStorageImpl::Keys",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
auto cb = base::BindOnce(
[](base::TimeTicks start_time, int64_t trace_id,
blink::mojom::CacheStorage::KeysCallback callback,
std::vector<std::string> cache_names) {
std::vector<base::string16> string16s;
for (const auto& name : cache_names) {
string16s.push_back(base::UTF8ToUTF16(name));
}
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.CacheStorage.Browser.Keys",
base::TimeTicks::Now() - start_time);
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheStorageImpl::Keys::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "key_list",
CacheStorageTracedValue(string16s));
std::move(callback).Run(string16s);
},
base::TimeTicks::Now(), trace_id, std::move(callback));
content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
if (!cache_storage) {
std::move(cb).Run(std::vector<std::string>());
return;
}
cache_storage->EnumerateCaches(trace_id, std::move(cb));
}
void Delete(const base::string16& cache_name,
int64_t trace_id,
blink::mojom::CacheStorage::DeleteCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::string utf8_cache_name = base::UTF16ToUTF8(cache_name);
TRACE_EVENT_WITH_FLOW1("CacheStorage",
"CacheStorageDispatchHost::CacheStorageImpl::Delete",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"cache_name", utf8_cache_name);
auto cb = base::BindOnce(
[](base::TimeTicks start_time, int64_t trace_id,
blink::mojom::CacheStorage::DeleteCallback callback,
CacheStorageError error) {
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.CacheStorage.Browser.Delete",
base::TimeTicks::Now() - start_time);
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheStorageImpl::Delete::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "status",
CacheStorageTracedValue(error));
std::move(callback).Run(error);
},
base::TimeTicks::Now(), trace_id, std::move(callback));
content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
if (!cache_storage) {
std::move(cb).Run(MakeErrorStorage(ErrorStorageType::kStorageHandleNull));
return;
}
cache_storage->DoomCache(utf8_cache_name, trace_id, std::move(cb));
}
void Has(const base::string16& cache_name,
int64_t trace_id,
blink::mojom::CacheStorage::HasCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::string utf8_cache_name = base::UTF16ToUTF8(cache_name);
TRACE_EVENT_WITH_FLOW1("CacheStorage",
"CacheStorageDispatchHost::CacheStorageImpl::Has",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"cache_name", utf8_cache_name);
auto cb = base::BindOnce(
[](base::TimeTicks start_time, int64_t trace_id,
blink::mojom::CacheStorage::HasCallback callback, bool has_cache,
CacheStorageError error) {
if (!has_cache)
error = CacheStorageError::kErrorNotFound;
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheStorageImpl::Has::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "status",
CacheStorageTracedValue(error));
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.CacheStorage.Browser.Has",
base::TimeTicks::Now() - start_time);
std::move(callback).Run(error);
},
base::TimeTicks::Now(), trace_id, std::move(callback));
content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
if (!cache_storage) {
std::move(cb).Run(/* has_cache = */ false,
MakeErrorStorage(ErrorStorageType::kStorageHandleNull));
return;
}
cache_storage->HasCache(utf8_cache_name, trace_id, std::move(cb));
}
void Match(blink::mojom::FetchAPIRequestPtr request,
blink::mojom::MultiCacheQueryOptionsPtr match_options,
bool in_related_fetch_event,
int64_t trace_id,
blink::mojom::CacheStorage::MatchCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
TRACE_EVENT_WITH_FLOW2("CacheStorage",
"CacheStorageDispatchHost::CacheStorageImpl::Match",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"request", CacheStorageTracedValue(request),
"options", CacheStorageTracedValue(match_options));
auto cb = BindOnce(
[](base::TimeTicks start_time, bool match_all_caches,
bool in_related_fetch_event, int64_t trace_id,
blink::mojom::CacheStorage::MatchCallback callback,
CacheStorageError error,
blink::mojom::FetchAPIResponsePtr response) {
base::TimeDelta elapsed = base::TimeTicks::Now() - start_time;
if (match_all_caches) {
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.CacheStorage.Browser.MatchAllCaches",
elapsed);
} else {
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.CacheStorage.Browser.MatchOneCache",
elapsed);
}
if (error != CacheStorageError::kSuccess) {
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheStorageImpl::Match::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "status",
CacheStorageTracedValue(error));
std::move(callback).Run(
blink::mojom::MatchResult::NewStatus(error));
return;
}
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheStorageImpl::Match::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "response",
CacheStorageTracedValue(response));
blink::mojom::MatchResultPtr result;
if (in_related_fetch_event) {
result = EagerlyReadResponseBody(std::move(response));
} else {
result =
blink::mojom::MatchResult::NewResponse(std::move(response));
}
std::move(callback).Run(std::move(result));
},
base::TimeTicks::Now(), !match_options->cache_name,
in_related_fetch_event, trace_id, std::move(callback));
content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
if (!cache_storage) {
std::move(cb).Run(CacheStorageError::kErrorNotFound, nullptr);
return;
}
if (!match_options->cache_name) {
cache_storage->MatchAllCaches(std::move(request),
std::move(match_options->query_options),
trace_id, std::move(cb));
return;
}
std::string cache_name = base::UTF16ToUTF8(*match_options->cache_name);
cache_storage->MatchCache(std::move(cache_name), std::move(request),
std::move(match_options->query_options), trace_id,
std::move(cb));
}
void Open(const base::string16& cache_name,
int64_t trace_id,
blink::mojom::CacheStorage::OpenCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::string utf8_cache_name = base::UTF16ToUTF8(cache_name);
TRACE_EVENT_WITH_FLOW1("CacheStorage",
"CacheStorageDispatchHost::CacheStorageImpl::Open",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"cache_name", utf8_cache_name);
content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
auto cb =
base::BindOnce(
[](base::WeakPtr<CacheStorageImpl> self, base::TimeTicks start_time,
int64_t trace_id,
blink::mojom::CacheStorage::OpenCallback callback,
CacheStorageCacheHandle cache_handle, CacheStorageError error) {
if (!self)
return;
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.CacheStorage.Browser.Open",
base::TimeTicks::Now() - start_time);
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
"CacheStorageDispatchHost::CacheStorageImpl::Open::Callback",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"status", CacheStorageTracedValue(error));
if (error != CacheStorageError::kSuccess) {
std::move(callback).Run(
blink::mojom::OpenResult::NewStatus(error));
return;
}
mojo::PendingAssociatedRemote<blink::mojom::CacheStorageCache>
pending_remote;
auto cache_impl =
std::make_unique<CacheImpl>(std::move(cache_handle));
self->owner_->AddCacheReceiver(
std::move(cache_impl),
pending_remote.InitWithNewEndpointAndPassReceiver());
std::move(callback).Run(blink::mojom::OpenResult::NewCache(
std::move(pending_remote)));
},
weak_factory_.GetWeakPtr(), base::TimeTicks::Now(), trace_id,
std::move(callback));
if (!cache_storage) {
std::move(cb).Run(CacheStorageCacheHandle(),
MakeErrorStorage(ErrorStorageType::kStorageHandleNull));
return;
}
cache_storage->OpenCache(utf8_cache_name, trace_id, std::move(cb));
}
private:
// Helper method that returns the current CacheStorageHandle value. If the
// handle is closed, then it attempts to open a new CacheStorageHandle
// automatically. This automatic open is necessary to re-attach to the
// backend after the browser storage has been wiped.
content::CacheStorage* GetOrCreateCacheStorage() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(owner_);
if (!cache_storage_handle_.value())
cache_storage_handle_ = owner_->OpenCacheStorage(origin_);
return cache_storage_handle_.value();
}
// Owns this.
CacheStorageDispatcherHost* const owner_;
const url::Origin origin_;
CacheStorageHandle cache_storage_handle_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<CacheStorageImpl> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(CacheStorageImpl);
};
CacheStorageDispatcherHost::CacheStorageDispatcherHost() = default;
CacheStorageDispatcherHost::~CacheStorageDispatcherHost() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void CacheStorageDispatcherHost::Init(CacheStorageContextImpl* context) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
context_ = context;
}
void CacheStorageDispatcherHost::AddReceiver(
mojo::PendingReceiver<blink::mojom::CacheStorage> receiver,
const url::Origin& origin) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto impl = std::make_unique<CacheStorageImpl>(this, origin);
receivers_.Add(std::move(impl), std::move(receiver));
}
void CacheStorageDispatcherHost::AddCacheReceiver(
std::unique_ptr<CacheImpl> cache_impl,
mojo::PendingAssociatedReceiver<blink::mojom::CacheStorageCache> receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
cache_receivers_.Add(std::move(cache_impl), std::move(receiver));
}
CacheStorageHandle CacheStorageDispatcherHost::OpenCacheStorage(
const url::Origin& origin) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!context_ || !context_->CacheManager() ||
!OriginCanAccessCacheStorage(origin))
return CacheStorageHandle();
return context_->CacheManager()->OpenCacheStorage(
origin, CacheStorageOwner::kCacheAPI);
}
} // namespace content