blob: 855e3ba7254a86f07735d009455f124db1881172 [file] [log] [blame]
// 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 "third_party/blink/renderer/modules/storage/storage_controller.h"
#include "base/feature_list.h"
#include "base/sys_info.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/interface_provider.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_storage_area.h"
#include "third_party/blink/public/platform/web_storage_namespace.h"
#include "third_party/blink/renderer/core/frame/content_settings_client.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/modules/storage/cached_storage_area.h"
#include "third_party/blink/renderer/modules/storage/storage_namespace.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
namespace blink {
namespace {
#define STATIC_ASSERT_MATCHING_ENUM(enum_name1, enum_name2) \
static_assert(static_cast<int>(enum_name1) == static_cast<int>(enum_name2), \
"mismatching enums: " #enum_name1)
STATIC_ASSERT_MATCHING_ENUM(StorageArea::StorageType::kLocalStorage,
ContentSettingsClient::StorageType::kLocal);
STATIC_ASSERT_MATCHING_ENUM(StorageArea::StorageType::kSessionStorage,
ContentSettingsClient::StorageType::kSession);
const size_t kStorageControllerTotalCacheLimitInBytesLowEnd = 1 * 1024 * 1024;
const size_t kStorageControllerTotalCacheLimitInBytes = 5 * 1024 * 1024;
mojom::blink::StoragePartitionServicePtr GetAndCreateStorageInterface() {
mojom::blink::StoragePartitionServicePtr ptr;
Platform::Current()->GetInterfaceProvider()->GetInterface(
mojo::MakeRequest(&ptr));
return ptr;
}
} // namespace
// static
StorageController* StorageController::GetInstance() {
DEFINE_STATIC_LOCAL(
StorageController, gCachedStorageAreaController,
(Platform::Current()->MainThread()->Scheduler()->IPCTaskRunner(),
GetAndCreateStorageInterface(),
base::SysInfo::IsLowEndDevice()
? kStorageControllerTotalCacheLimitInBytesLowEnd
: kStorageControllerTotalCacheLimitInBytes));
return &gCachedStorageAreaController;
}
// static
bool StorageController::CanAccessStorageArea(LocalFrame* frame,
StorageArea::StorageType type) {
DCHECK(frame->GetContentSettingsClient());
return frame->GetContentSettingsClient()->AllowStorage(
static_cast<ContentSettingsClient::StorageType>(type));
}
StorageController::StorageController(
scoped_refptr<base::SingleThreadTaskRunner> ipc_runner,
mojom::blink::StoragePartitionServicePtr storage_partition_service,
size_t total_cache_limit)
: ipc_runner_(std::move(ipc_runner)),
namespaces_(new HeapHashMap<String, WeakMember<StorageNamespace>>()),
total_cache_limit_(total_cache_limit),
storage_partition_service_(std::move(storage_partition_service)) {}
StorageNamespace* StorageController::CreateSessionStorageNamespace(
const String& namespace_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// There is an edge case where a user closes a tab that has other tabs in the
// same process, then restores that tab. The old namespace might still be
// around.
auto it = namespaces_->find(namespace_id);
if (it != namespaces_->end())
return it->value;
StorageNamespace* ns = nullptr;
if (base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)) {
ns = new StorageNamespace(this, namespace_id);
} else {
auto namespace_str = StringUTF8Adaptor(namespace_id);
auto web_namespace = Platform::Current()->CreateSessionStorageNamespace(
namespace_str.AsStringPiece());
if (!web_namespace)
return nullptr;
ns = new StorageNamespace(std::move(web_namespace));
}
namespaces_->insert(namespace_id, ns);
return ns;
}
size_t StorageController::TotalCacheSize() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
size_t total = 0;
if (local_storage_namespace_)
total = local_storage_namespace_->TotalCacheSize();
for (const auto& pair : *namespaces_)
total += pair.value->TotalCacheSize();
return total;
}
void StorageController::ClearAreasIfNeeded() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (TotalCacheSize() < total_cache_limit_)
return;
if (local_storage_namespace_)
local_storage_namespace_->CleanUpUnusedAreas();
for (auto& pair : *namespaces_)
pair.value->CleanUpUnusedAreas();
}
scoped_refptr<CachedStorageArea> StorageController::GetLocalStorageArea(
const SecurityOrigin* origin) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage));
EnsureLocalStorageNamespaceCreated();
return local_storage_namespace_->GetCachedArea(origin);
}
std::unique_ptr<WebStorageArea> StorageController::GetWebLocalStorageArea(
const SecurityOrigin* origin) {
DCHECK(IsMainThread());
CHECK(!base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage));
EnsureLocalStorageNamespaceCreated();
return local_storage_namespace_->GetWebStorageArea(origin);
}
void StorageController::AddLocalStorageInspectorStorageAgent(
InspectorDOMStorageAgent* agent) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureLocalStorageNamespaceCreated();
local_storage_namespace_->AddInspectorStorageAgent(agent);
}
void StorageController::RemoveLocalStorageInspectorStorageAgent(
InspectorDOMStorageAgent* agent) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureLocalStorageNamespaceCreated();
local_storage_namespace_->RemoveInspectorStorageAgent(agent);
}
void StorageController::DidDispatchLocalStorageEvent(
const SecurityOrigin* origin,
const String& key,
const String& old_value,
const String& new_value) {
if (local_storage_namespace_) {
local_storage_namespace_->DidDispatchStorageEvent(origin, key, old_value,
new_value);
}
}
void StorageController::EnsureLocalStorageNamespaceCreated() {
if (local_storage_namespace_)
return;
if (base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)) {
local_storage_namespace_ = new StorageNamespace(this);
} else {
local_storage_namespace_ = new StorageNamespace(
Platform::Current()->CreateLocalStorageNamespace());
}
}
} // namespace blink