blob: 8d60f272df803647c4853bbac32ad06556d2d945 [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 "third_party/blink/renderer/modules/cache_storage/global_cache_storage.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/modules/cache_storage/cache_storage.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/supplementable.h"
namespace blink {
namespace {
template <typename T>
class GlobalCacheStorageImpl final
: public GarbageCollected<GlobalCacheStorageImpl<T>>,
public Supplement<T> {
public:
static const char kSupplementName[];
static GlobalCacheStorageImpl& From(T& supplementable,
ExecutionContext* execution_context) {
GlobalCacheStorageImpl* supplement =
Supplement<T>::template From<GlobalCacheStorageImpl>(supplementable);
if (!supplement) {
supplement = MakeGarbageCollected<GlobalCacheStorageImpl>();
Supplement<T>::ProvideTo(supplementable, supplement);
}
return *supplement;
}
GlobalCacheStorageImpl() : Supplement<T>(nullptr) {}
~GlobalCacheStorageImpl() = default;
CacheStorage* Caches(T& fetching_scope, ExceptionState& exception_state) {
ExecutionContext* context = fetching_scope.GetExecutionContext();
if (!context->GetSecurityOrigin()->CanAccessCacheStorage()) {
if (context->IsSandboxed(
network::mojom::blink::WebSandboxFlags::kOrigin)) {
exception_state.ThrowSecurityError(
"Cache storage is disabled because the context is sandboxed and "
"lacks the 'allow-same-origin' flag.");
} else if (context->Url().ProtocolIs("data")) {
exception_state.ThrowSecurityError(
"Cache storage is disabled inside 'data:' URLs.");
} else {
exception_state.ThrowSecurityError(
"Access to cache storage is denied.");
}
return nullptr;
}
if (context->GetSecurityOrigin()->IsLocal()) {
UseCounter::Count(context, WebFeature::kFileAccessedCache);
}
if (!caches_) {
if (&context->GetBrowserInterfaceBroker() ==
&GetEmptyBrowserInterfaceBroker()) {
exception_state.ThrowSecurityError(
"Cache storage isn't available on detached context. No browser "
"interface broker.");
return nullptr;
}
caches_ = MakeGarbageCollected<CacheStorage>(
context, GlobalFetch::ScopedFetcher::From(fetching_scope));
}
return caches_;
}
void Trace(Visitor* visitor) const override {
visitor->Trace(caches_);
Supplement<T>::Trace(visitor);
}
private:
Member<CacheStorage> caches_;
};
// static
template <typename T>
const char GlobalCacheStorageImpl<T>::kSupplementName[] =
"GlobalCacheStorageImpl";
} // namespace
CacheStorage* GlobalCacheStorage::caches(LocalDOMWindow& window,
ExceptionState& exception_state) {
return GlobalCacheStorageImpl<LocalDOMWindow>::From(
window, window.GetExecutionContext())
.Caches(window, exception_state);
}
CacheStorage* GlobalCacheStorage::caches(WorkerGlobalScope& worker,
ExceptionState& exception_state) {
return GlobalCacheStorageImpl<WorkerGlobalScope>::From(
worker, worker.GetExecutionContext())
.Caches(worker, exception_state);
}
} // namespace blink