blob: 7277c56f7b7f7a24c74d3c84b52e34190b80690e [file] [log] [blame]
// Copyright 2014 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 "third_party/blink/renderer/modules/cache_storage/cache_storage.h"
#include <memory>
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/fetch/request.h"
#include "third_party/blink/renderer/core/fetch/response.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/modules/cache_storage/cache_storage_error.h"
#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
namespace blink {
CacheStorage* CacheStorage::Create(ExecutionContext* context,
GlobalFetch::ScopedFetcher* fetcher) {
return new CacheStorage(context, fetcher);
}
ScriptPromise CacheStorage::open(ScriptState* script_state,
const String& cache_name) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
cache_storage_ptr_->Open(
cache_name,
WTF::Bind(
[](ScriptPromiseResolver* resolver,
GlobalFetch::ScopedFetcher* fetcher, TimeTicks start_time,
mojom::blink::OpenResultPtr result) {
if (!resolver->GetExecutionContext() ||
resolver->GetExecutionContext()->IsContextDestroyed())
return;
if (result->is_status()) {
switch (result->get_status()) {
case mojom::blink::CacheStorageError::kErrorNotFound:
case mojom::blink::CacheStorageError::kErrorStorage:
resolver->Resolve();
break;
default:
resolver->Reject(
CacheStorageError::CreateException(result->get_status()));
break;
}
} else {
UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Open",
TimeTicks::Now() - start_time);
resolver->Resolve(
Cache::Create(fetcher, std::move(result->get_cache())));
}
},
WrapPersistent(resolver), WrapPersistent(scoped_fetcher_.Get()),
TimeTicks::Now()));
return resolver->Promise();
}
ScriptPromise CacheStorage::has(ScriptState* script_state,
const String& cache_name) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
cache_storage_ptr_->Has(
cache_name,
WTF::Bind(
[](ScriptPromiseResolver* resolver, TimeTicks start_time,
mojom::blink::CacheStorageError result) {
if (!resolver->GetExecutionContext() ||
resolver->GetExecutionContext()->IsContextDestroyed())
return;
switch (result) {
case mojom::blink::CacheStorageError::kSuccess:
UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Has",
TimeTicks::Now() - start_time);
resolver->Resolve(true);
break;
case mojom::blink::CacheStorageError::kErrorNotFound:
resolver->Resolve(false);
break;
default:
resolver->Reject(CacheStorageError::CreateException(result));
break;
}
},
WrapPersistent(resolver), TimeTicks::Now()));
return resolver->Promise();
}
ScriptPromise CacheStorage::Delete(ScriptState* script_state,
const String& cache_name) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
cache_storage_ptr_->Delete(
cache_name,
WTF::Bind(
[](ScriptPromiseResolver* resolver, TimeTicks start_time,
mojom::blink::CacheStorageError result) {
if (!resolver->GetExecutionContext() ||
resolver->GetExecutionContext()->IsContextDestroyed())
return;
switch (result) {
case mojom::blink::CacheStorageError::kSuccess:
UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Delete",
TimeTicks::Now() - start_time);
resolver->Resolve(true);
break;
case mojom::blink::CacheStorageError::kErrorStorage:
case mojom::blink::CacheStorageError::kErrorNotFound:
resolver->Resolve(false);
break;
default:
resolver->Reject(CacheStorageError::CreateException(result));
break;
}
},
WrapPersistent(resolver), TimeTicks::Now()));
return resolver->Promise();
}
ScriptPromise CacheStorage::keys(ScriptState* script_state) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
cache_storage_ptr_->Keys(WTF::Bind(
[](ScriptPromiseResolver* resolver, TimeTicks start_time,
const Vector<String>& keys) {
if (!resolver->GetExecutionContext() ||
resolver->GetExecutionContext()->IsContextDestroyed())
return;
UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Keys",
TimeTicks::Now() - start_time);
resolver->Resolve(keys);
},
WrapPersistent(resolver), TimeTicks::Now()));
return resolver->Promise();
}
ScriptPromise CacheStorage::match(ScriptState* script_state,
const RequestInfo& request,
const CacheQueryOptions* options,
ExceptionState& exception_state) {
DCHECK(!request.IsNull());
if (request.IsRequest())
return MatchImpl(script_state, request.GetAsRequest(), options);
Request* new_request =
Request::Create(script_state, request.GetAsUSVString(), exception_state);
if (exception_state.HadException())
return ScriptPromise();
return MatchImpl(script_state, new_request, options);
}
ScriptPromise CacheStorage::MatchImpl(ScriptState* script_state,
const Request* request,
const CacheQueryOptions* options) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
const ScriptPromise promise = resolver->Promise();
if (request->method() != http_names::kGET && !options->ignoreMethod()) {
resolver->Resolve();
return promise;
}
cache_storage_ptr_->Match(
request->CreateFetchAPIRequest(), Cache::ToQueryParams(options),
WTF::Bind(
[](ScriptPromiseResolver* resolver, TimeTicks start_time,
const CacheQueryOptions* options,
mojom::blink::MatchResultPtr result) {
if (!resolver->GetExecutionContext() ||
resolver->GetExecutionContext()->IsContextDestroyed())
return;
if (result->is_status()) {
switch (result->get_status()) {
case mojom::CacheStorageError::kErrorNotFound:
case mojom::CacheStorageError::kErrorStorage:
case mojom::CacheStorageError::kErrorCacheNameNotFound:
resolver->Resolve();
break;
default:
resolver->Reject(
CacheStorageError::CreateException(result->get_status()));
break;
}
} else {
TimeDelta elapsed = TimeTicks::Now() - start_time;
UMA_HISTOGRAM_LONG_TIMES("ServiceWorkerCache.CacheStorage.Match2",
elapsed);
if (options->hasIgnoreSearch() && options->ignoreSearch()) {
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.CacheStorage.Match2."
"IgnoreSearchEnabled",
elapsed);
} else {
UMA_HISTOGRAM_LONG_TIMES(
"ServiceWorkerCache.CacheStorage.Match2."
"IgnoreSearchDisabled",
elapsed);
}
ScriptState::Scope scope(resolver->GetScriptState());
resolver->Resolve(Response::Create(resolver->GetScriptState(),
*result->get_response()));
}
},
WrapPersistent(resolver), TimeTicks::Now(), WrapPersistent(options)));
return promise;
}
CacheStorage::CacheStorage(ExecutionContext* context,
GlobalFetch::ScopedFetcher* fetcher)
: scoped_fetcher_(fetcher) {
// Service workers may already have a CacheStoragePtr provided as an
// optimization.
if (auto* service_worker = DynamicTo<ServiceWorkerGlobalScope>(context)) {
mojom::blink::CacheStoragePtrInfo info = service_worker->TakeCacheStorage();
if (info) {
cache_storage_ptr_ = RevocableInterfacePtr<mojom::blink::CacheStorage>(
std::move(info), context->GetInterfaceInvalidator());
return;
}
}
context->GetInterfaceProvider()->GetInterface(
MakeRequest(&cache_storage_ptr_, context->GetInterfaceInvalidator()));
}
CacheStorage::~CacheStorage() = default;
void CacheStorage::Trace(blink::Visitor* visitor) {
visitor->Trace(scoped_fetcher_);
ScriptWrappable::Trace(visitor);
}
} // namespace blink