blob: 3dc641a72981049ffb547f868cbe42b2ebe87760 [file] [log] [blame]
/*
* Copyright (C) 2009 Google Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/modules/storage/storage_namespace.h"
#include <memory>
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_security_origin.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/public/web/web_view_client.h"
#include "third_party/blink/renderer/modules/storage/cached_storage_area.h"
#include "third_party/blink/renderer/modules/storage/inspector_dom_storage_agent.h"
#include "third_party/blink/renderer/modules/storage/storage_area.h"
#include "third_party/blink/renderer/modules/storage/storage_controller.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
const char StorageNamespace::kSupplementName[] = "SessionStorageNamespace";
StorageNamespace::StorageNamespace(StorageController* controller)
: controller_(controller) {
CHECK(base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage));
}
StorageNamespace::StorageNamespace(StorageController* controller,
const String& namespace_id)
: controller_(controller), namespace_id_(namespace_id) {
CHECK(base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage));
}
StorageNamespace::StorageNamespace(
std::unique_ptr<WebStorageNamespace> web_storage_namespace)
: controller_(nullptr),
namespace_id_(web_storage_namespace->GetNamespaceId()),
web_storage_namespace_(std::move(web_storage_namespace)) {
CHECK(!base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage));
}
StorageNamespace::~StorageNamespace() = default;
// static
void StorageNamespace::ProvideSessionStorageNamespaceTo(Page& page,
WebViewClient* client) {
if (client) {
if (client->GetSessionStorageNamespaceId().empty())
return;
auto* ss_namespace =
StorageController::GetInstance()->CreateSessionStorageNamespace(
String(client->GetSessionStorageNamespaceId().data(),
client->GetSessionStorageNamespaceId().size()));
if (!ss_namespace)
return;
ProvideTo(page, ss_namespace);
}
}
scoped_refptr<CachedStorageArea> StorageNamespace::GetCachedArea(
const SecurityOrigin* origin_ptr) {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class CacheMetrics {
kMiss = 0, // Area not in cache.
kHit = 1, // Area with refcount = 0 loaded from cache.
kUnused = 2, // Cache was not used. Area had refcount > 0.
kMaxValue = kUnused,
};
CacheMetrics metric = CacheMetrics::kMiss;
scoped_refptr<CachedStorageArea> result;
auto cache_it = cached_areas_.find(origin_ptr);
if (cache_it != cached_areas_.end()) {
metric = cache_it->value->HasOneRef() ? CacheMetrics::kHit
: CacheMetrics::kUnused;
result = cache_it->value;
}
if (IsSessionStorage())
LOCAL_HISTOGRAM_ENUMERATION("SessionStorage.RendererAreaCacheHit", metric);
else
UMA_HISTOGRAM_ENUMERATION("LocalStorage.RendererAreaCacheHit", metric);
if (result)
return result;
scoped_refptr<const SecurityOrigin> origin(origin_ptr);
controller_->ClearAreasIfNeeded();
if (IsSessionStorage()) {
EnsureConnected();
mojom::blink::StorageAreaAssociatedPtr area_ptr;
namespace_->OpenArea(origin,
MakeRequest(&area_ptr, controller_->IPCTaskRunner()));
result = CachedStorageArea::CreateForSessionStorage(
origin, std::move(area_ptr), controller_->IPCTaskRunner(), this);
} else {
mojom::blink::StorageAreaPtr area_ptr;
controller_->storage_partition_service()->OpenLocalStorage(
origin, MakeRequest(&area_ptr, controller_->IPCTaskRunner()));
result = CachedStorageArea::CreateForLocalStorage(
origin, std::move(area_ptr), controller_->IPCTaskRunner(), this);
}
cached_areas_.insert(std::move(origin), result);
return result;
}
void StorageNamespace::CloneTo(const String& target) {
CHECK(base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage));
DCHECK(IsSessionStorage()) << "Cannot clone a local storage namespace.";
EnsureConnected();
namespace_->Clone(target);
}
size_t StorageNamespace::TotalCacheSize() const {
size_t total = 0;
for (const auto& it : cached_areas_)
total += it.value->memory_used();
return total;
}
void StorageNamespace::CleanUpUnusedAreas() {
Vector<const SecurityOrigin*, 16> to_remove;
for (const auto& area : cached_areas_) {
if (area.value->HasOneRef())
to_remove.push_back(area.key.get());
}
cached_areas_.RemoveAll(to_remove);
}
void StorageNamespace::AddInspectorStorageAgent(
InspectorDOMStorageAgent* agent) {
inspector_agents_.insert(agent);
}
void StorageNamespace::RemoveInspectorStorageAgent(
InspectorDOMStorageAgent* agent) {
inspector_agents_.erase(agent);
}
void StorageNamespace::Trace(Visitor* visitor) {
visitor->Trace(inspector_agents_);
Supplement<Page>::Trace(visitor);
}
void StorageNamespace::DidDispatchStorageEvent(const SecurityOrigin* origin,
const String& key,
const String& old_value,
const String& new_value) {
for (InspectorDOMStorageAgent* agent : inspector_agents_) {
agent->DidDispatchDOMStorageEvent(
key, old_value, new_value,
IsSessionStorage() ? StorageArea::StorageType::kSessionStorage
: StorageArea::StorageType::kLocalStorage,
origin);
}
}
std::unique_ptr<WebStorageArea> StorageNamespace::GetWebStorageArea(
const SecurityOrigin* origin) {
CHECK(!base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage));
return base::WrapUnique(
web_storage_namespace_->CreateStorageArea(WebSecurityOrigin(origin)));
}
void StorageNamespace::EnsureConnected() {
DCHECK(IsSessionStorage());
if (namespace_)
return;
auto request = MakeRequest(&namespace_, controller_->IPCTaskRunner());
controller_->storage_partition_service()->OpenSessionStorage(
namespace_id_, std::move(request));
}
} // namespace blink