blob: d61c122c54b3dc26810e393dd7599bacab556139 [file] [log] [blame]
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/storage/store/memory_store.h"
#include <map>
#include <string>
#include <tuple>
#include <vector>
#include "base/debug/trace_event.h"
#include "cobalt/storage/storage_constants.h"
#include "cobalt/storage/store/storage.pb.h"
#include "googleurl/src/gurl.h"
#include "nb/memory_scope.h"
namespace cobalt {
namespace storage {
namespace {
bool IsValidFormat(const std::vector<uint8>& buffer) {
return buffer.size() >= kStorageHeaderSize &&
memcmp(buffer.data(), kStorageHeader, kStorageHeaderSize) == 0;
}
} // namespace
// Using Pimpl design pattern to hide protobuf implementation details.
// The generated proto code (including the header) needs special build
// configuration to work as expected. Which means adding special build settings
// to any place where the headers is included.
class MemoryStore::Impl {
public:
// Initialization
Impl();
bool Initialize(const std::vector<uint8>& in);
// Serialization
bool Serialize(std::vector<uint8>* out) const;
// Cookies
void GetAllCookies(std::vector<net::CanonicalCookie*>* cookies) const;
void AddCookie(const net::CanonicalCookie& cc, int64 expiration_time_us);
void UpdateCookieAccessTime(const net::CanonicalCookie& cc, int64 time_us);
void DeleteCookie(const net::CanonicalCookie& cc);
// Local Storage
void ReadAllLocalStorage(const loader::Origin& origin,
LocalStorageMap* local_storage_map) const;
void WriteToLocalStorage(const loader::Origin& origin, const std::string& key,
const std::string& value);
void DeleteFromLocalStorage(const loader::Origin& origin,
const std::string& key);
void ClearLocalStorage(const loader::Origin& origin);
// Disable copying
Impl(const Impl& store) = delete;
Impl& operator=(const Impl& store) = delete;
private:
typedef std::tuple<std::string, std::string, std::string> CookieKey;
std::map<CookieKey, Cookie> cookies_map_;
typedef std::map<std::string, std::string> LocalStorageKeyValueMap;
typedef std::map<std::string, LocalStorageKeyValueMap>
LocalStorageByOriginMap;
LocalStorageByOriginMap local_storage_by_origin_map_;
};
MemoryStore::Impl::Impl() {}
bool MemoryStore::Impl::Initialize(const std::vector<uint8>& in) {
TRACK_MEMORY_SCOPE("Storage");
if (!IsValidFormat(in)) {
LOG(ERROR) << "Invalid format with size=" << in.size();
return false;
}
Storage storage_data;
if (!storage_data.ParseFromArray(
reinterpret_cast<const char*>(in.data() + kStorageHeaderSize),
in.size() - kStorageHeaderSize)) {
LOG(ERROR) << "Unable to parse storage with size" << in.size();
return false;
}
for (auto& cookie : storage_data.cookies()) {
cookies_map_[std::make_tuple(cookie.domain(), cookie.path(),
cookie.name())] = cookie;
}
for (const auto& local_storages : storage_data.local_storages()) {
for (const auto& local_storage_entry :
local_storages.local_storage_entries()) {
GURL gurl(local_storages.serialized_origin());
loader::Origin origin(gurl);
if (origin.is_opaque()) {
LOG(WARNING) << "Ignoring storage for opaque origin "
<< local_storages.serialized_origin();
continue;
}
local_storage_by_origin_map_[origin.SerializedOrigin()]
[local_storage_entry.key()] =
local_storage_entry.value();
}
}
return true;
}
bool MemoryStore::Impl::Serialize(std::vector<uint8>* out) const {
TRACK_MEMORY_SCOPE("Storage");
Storage storage_data;
for (const auto& cookie_pair : cookies_map_) {
*(storage_data.add_cookies()) = cookie_pair.second;
}
for (const auto& origin_storage_pair : local_storage_by_origin_map_) {
LocalStorage* local_storage = storage_data.add_local_storages();
local_storage->set_serialized_origin(origin_storage_pair.first);
for (const auto& key_value_pair : origin_storage_pair.second) {
LocalStorageEntry* local_storage_entry =
local_storage->add_local_storage_entries();
local_storage_entry->set_key(key_value_pair.first);
local_storage_entry->set_value(key_value_pair.second);
}
}
size_t size = storage_data.ByteSize();
out->resize(kStorageHeaderSize + size);
char* buffer_ptr = reinterpret_cast<char*>(out->data());
memcpy(buffer_ptr, kStorageHeader, kStorageHeaderSize);
if (size > 0 &&
!storage_data.SerializeToArray(buffer_ptr + kStorageHeaderSize, size)) {
LOG(ERROR) << "Failed to serialize message with size=" << size;
return false;
}
return true;
}
void MemoryStore::Impl::GetAllCookies(
std::vector<net::CanonicalCookie*>* cookies) const {
TRACK_MEMORY_SCOPE("Storage");
for (const auto& cookie_pair : cookies_map_) {
// We create a CanonicalCookie directly through its constructor instead of
// through CanonicalCookie::Create() and its sanitization because these
// values are just serialized from a former instance of a CanonicalCookie
// object that *was* created through CanonicalCookie::Create().
scoped_ptr<net::CanonicalCookie> cookie(new net::CanonicalCookie(
GURL(""), cookie_pair.second.name(), cookie_pair.second.value(),
cookie_pair.second.domain(), cookie_pair.second.path(),
"" /* mac_key */, "" /* mac_algorithm */,
base::Time::FromInternalValue(cookie_pair.second.creation_time_us()),
base::Time::FromInternalValue(cookie_pair.second.expiration_time_us()),
base::Time::FromInternalValue(cookie_pair.second.last_access_time_us()),
cookie_pair.second.secure(), cookie_pair.second.http_only()));
cookies->push_back(cookie.release());
}
}
void MemoryStore::Impl::AddCookie(const net::CanonicalCookie& cc,
int64 expiration_time_us) {
TRACK_MEMORY_SCOPE("Storage");
Cookie cookie;
cookie.set_domain(cc.Domain());
cookie.set_path(cc.Path());
cookie.set_name(cc.Name());
cookie.set_value(cc.Value());
cookie.set_secure(cc.IsSecure());
cookie.set_http_only(cc.IsHttpOnly());
cookie.set_creation_time_us(cc.CreationDate().ToInternalValue());
cookie.set_expiration_time_us(expiration_time_us);
cookie.set_last_access_time_us(cc.LastAccessDate().ToInternalValue());
CookieKey key = std::make_tuple(cc.Domain(), cc.Path(), cc.Name());
cookies_map_[key] = cookie;
}
void MemoryStore::Impl::UpdateCookieAccessTime(const net::CanonicalCookie& cc,
int64 time_us) {
CookieKey key = std::make_tuple(cc.Domain(), cc.Path(), cc.Name());
cookies_map_[key].set_last_access_time_us(time_us);
}
void MemoryStore::Impl::DeleteCookie(const net::CanonicalCookie& cc) {
CookieKey key = std::make_tuple(cc.Domain(), cc.Path(), cc.Name());
cookies_map_.erase(key);
}
void MemoryStore::Impl::ReadAllLocalStorage(
const loader::Origin& origin, LocalStorageMap* local_storage_map) const {
TRACK_MEMORY_SCOPE("Storage");
const auto& it = local_storage_by_origin_map_.find(origin.SerializedOrigin());
if (it != local_storage_by_origin_map_.end()) {
local_storage_map->insert(it->second.begin(), it->second.end());
}
}
void MemoryStore::Impl::WriteToLocalStorage(const loader::Origin& origin,
const std::string& key,
const std::string& value) {
TRACK_MEMORY_SCOPE("Storage");
local_storage_by_origin_map_[origin.SerializedOrigin()][key] = value;
}
void MemoryStore::Impl::DeleteFromLocalStorage(const loader::Origin& origin,
const std::string& key) {
TRACK_MEMORY_SCOPE("Storage");
local_storage_by_origin_map_[origin.SerializedOrigin()].erase(key);
}
void MemoryStore::Impl::ClearLocalStorage(const loader::Origin& origin) {
TRACK_MEMORY_SCOPE("Storage");
local_storage_by_origin_map_[origin.SerializedOrigin()].clear();
}
MemoryStore::MemoryStore() { impl_.reset(new Impl()); }
bool MemoryStore::Initialize(const std::vector<uint8>& in) {
return impl_->Initialize(in);
}
bool MemoryStore::Serialize(std::vector<uint8>* out) const {
return impl_->Serialize(out);
}
void MemoryStore::GetAllCookies(
std::vector<net::CanonicalCookie*>* cookies) const {
impl_->GetAllCookies(cookies);
}
void MemoryStore::AddCookie(const net::CanonicalCookie& cc,
int64 expiration_time_us) {
impl_->AddCookie(cc, expiration_time_us);
}
void MemoryStore::UpdateCookieAccessTime(const net::CanonicalCookie& cc,
int64 time_us) {
impl_->UpdateCookieAccessTime(cc, time_us);
}
void MemoryStore::DeleteCookie(const net::CanonicalCookie& cc) {
impl_->DeleteCookie(cc);
}
void MemoryStore::ReadAllLocalStorage(
const loader::Origin& origin, LocalStorageMap* local_storage_map) const {
impl_->ReadAllLocalStorage(origin, local_storage_map);
}
void MemoryStore::WriteToLocalStorage(const loader::Origin& origin,
const std::string& key,
const std::string& value) {
impl_->WriteToLocalStorage(origin, key, value);
}
void MemoryStore::DeleteFromLocalStorage(const loader::Origin& origin,
const std::string& key) {
impl_->DeleteFromLocalStorage(origin, key);
}
void MemoryStore::ClearLocalStorage(const loader::Origin& origin) {
impl_->ClearLocalStorage(origin);
}
MemoryStore::~MemoryStore() {}
} // namespace storage
} // namespace cobalt