Commit 1bca97b2 authored by Daniel Murphy's avatar Daniel Murphy Committed by Commit Bot

[SessionStorage] Fixed re-use of data maps that were purged

When PurgeUnusedAreas is called, the unbound areas are destroyed. If one
of these areas was holding onto a data map that was cloned to another
area in a different namespace, a re-bind to that area created a new map
instead of using the already-existing one.

This change allows the SessionStorageNamespaceImpl to look up maps that
are already in use to possibly re-use a map that already exists.

R=mek@chromium.org

Bug: 866887
Change-Id: Ifdb14278bb223bbdcb877e4fddccd158968fb575
Reviewed-on: https://chromium-review.googlesource.com/1153770
Commit-Queue: Daniel Murphy <dmurph@chromium.org>
Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#578857}
parent a37ba3b9
...@@ -138,8 +138,7 @@ void SessionStorageContextMojo::OpenSessionStorage( ...@@ -138,8 +138,7 @@ void SessionStorageContextMojo::OpenSessionStorage(
if (!found->second->IsPopulated() && if (!found->second->IsPopulated() &&
!found->second->waiting_on_clone_population()) { !found->second->waiting_on_clone_population()) {
found->second->PopulateFromMetadata( found->second->PopulateFromMetadata(
database_.get(), metadata_.GetOrCreateNamespaceEntry(namespace_id), database_.get(), metadata_.GetOrCreateNamespaceEntry(namespace_id));
data_maps_);
} }
PurgeUnusedAreasIfNeeded(); PurgeUnusedAreasIfNeeded();
...@@ -439,6 +438,39 @@ bool SessionStorageContextMojo::OnMemoryDump( ...@@ -439,6 +438,39 @@ bool SessionStorageContextMojo::OnMemoryDump(
return true; return true;
} }
void SessionStorageContextMojo::SetDatabaseForTesting(
leveldb::mojom::LevelDBDatabaseAssociatedPtr database) {
DCHECK_EQ(connection_state_, NO_CONNECTION);
connection_state_ = CONNECTION_IN_PROGRESS;
database_ = std::move(database);
OnDatabaseOpened(true, leveldb::mojom::DatabaseError::OK);
}
void SessionStorageContextMojo::FlushAreaForTesting(
const std::string& namespace_id,
const url::Origin& origin) {
if (connection_state_ != CONNECTION_FINISHED)
return;
const auto& it = namespaces_.find(namespace_id);
if (it == namespaces_.end())
return;
it->second->FlushOriginForTesting(origin);
}
scoped_refptr<SessionStorageMetadata::MapData>
SessionStorageContextMojo::RegisterNewAreaMap(
SessionStorageMetadata::NamespaceEntry namespace_entry,
const url::Origin& origin) {
std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
scoped_refptr<SessionStorageMetadata::MapData> map_entry =
metadata_.RegisterNewMap(namespace_entry, origin, &save_operations);
database_->Write(std::move(save_operations),
base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
base::Unretained(this)));
return map_entry;
}
void SessionStorageContextMojo::OnDataMapCreation( void SessionStorageContextMojo::OnDataMapCreation(
const std::vector<uint8_t>& map_prefix, const std::vector<uint8_t>& map_prefix,
SessionStorageDataMap* map) { SessionStorageDataMap* map) {
...@@ -481,37 +513,13 @@ void SessionStorageContextMojo::OnCommitResult( ...@@ -481,37 +513,13 @@ void SessionStorageContextMojo::OnCommitResult(
} }
} }
void SessionStorageContextMojo::SetDatabaseForTesting( scoped_refptr<SessionStorageDataMap>
leveldb::mojom::LevelDBDatabaseAssociatedPtr database) { SessionStorageContextMojo::MaybeGetExistingDataMapForId(
DCHECK_EQ(connection_state_, NO_CONNECTION); const std::vector<uint8_t>& map_number_as_bytes) {
connection_state_ = CONNECTION_IN_PROGRESS; auto it = data_maps_.find(map_number_as_bytes);
database_ = std::move(database); if (it == data_maps_.end())
OnDatabaseOpened(true, leveldb::mojom::DatabaseError::OK); return nullptr;
} return base::WrapRefCounted(it->second);
void SessionStorageContextMojo::FlushAreaForTesting(
const std::string& namespace_id,
const url::Origin& origin) {
if (connection_state_ != CONNECTION_FINISHED)
return;
const auto& it = namespaces_.find(namespace_id);
if (it == namespaces_.end())
return;
it->second->FlushOriginForTesting(origin);
}
scoped_refptr<SessionStorageMetadata::MapData>
SessionStorageContextMojo::RegisterNewAreaMap(
SessionStorageMetadata::NamespaceEntry namespace_entry,
const url::Origin& origin) {
std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
scoped_refptr<SessionStorageMetadata::MapData> map_entry =
metadata_.RegisterNewMap(namespace_entry, origin, &save_operations);
database_->Write(std::move(save_operations),
base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
base::Unretained(this)));
return map_entry;
} }
void SessionStorageContextMojo::RegisterShallowClonedNamespace( void SessionStorageContextMojo::RegisterShallowClonedNamespace(
...@@ -555,17 +563,12 @@ void SessionStorageContextMojo::RegisterShallowClonedNamespace( ...@@ -555,17 +563,12 @@ void SessionStorageContextMojo::RegisterShallowClonedNamespace(
std::unique_ptr<SessionStorageNamespaceImplMojo> std::unique_ptr<SessionStorageNamespaceImplMojo>
SessionStorageContextMojo::CreateSessionStorageNamespaceImplMojo( SessionStorageContextMojo::CreateSessionStorageNamespaceImplMojo(
std::string namespace_id) { std::string namespace_id) {
SessionStorageNamespaceImplMojo::RegisterShallowClonedNamespace
add_namespace_callback = base::BindRepeating(
&SessionStorageContextMojo::RegisterShallowClonedNamespace,
base::Unretained(this));
SessionStorageAreaImpl::RegisterNewAreaMap map_id_callback = SessionStorageAreaImpl::RegisterNewAreaMap map_id_callback =
base::BindRepeating(&SessionStorageContextMojo::RegisterNewAreaMap, base::BindRepeating(&SessionStorageContextMojo::RegisterNewAreaMap,
base::Unretained(this)); base::Unretained(this));
return std::make_unique<SessionStorageNamespaceImplMojo>( return std::make_unique<SessionStorageNamespaceImplMojo>(
std::move(namespace_id), this, std::move(add_namespace_callback), std::move(namespace_id), this, std::move(map_id_callback), this);
std::move(map_id_callback));
} }
void SessionStorageContextMojo::DoDatabaseDelete( void SessionStorageContextMojo::DoDatabaseDelete(
......
...@@ -45,7 +45,8 @@ struct SessionStorageUsageInfo; ...@@ -45,7 +45,8 @@ struct SessionStorageUsageInfo;
// ShutdownAndDelete (on the correct task runner). // ShutdownAndDelete (on the correct task runner).
class CONTENT_EXPORT SessionStorageContextMojo class CONTENT_EXPORT SessionStorageContextMojo
: public base::trace_event::MemoryDumpProvider, : public base::trace_event::MemoryDumpProvider,
public SessionStorageDataMap::Listener { public SessionStorageDataMap::Listener,
public SessionStorageNamespaceImplMojo::Delegate {
public: public:
using GetStorageUsageCallback = using GetStorageUsageCallback =
base::OnceCallback<void(std::vector<SessionStorageUsageInfo>)>; base::OnceCallback<void(std::vector<SessionStorageUsageInfo>)>;
...@@ -123,12 +124,6 @@ class CONTENT_EXPORT SessionStorageContextMojo ...@@ -123,12 +124,6 @@ class CONTENT_EXPORT SessionStorageContextMojo
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override; base::trace_event::ProcessMemoryDump* pmd) override;
// SessionStorageAreaImpl::Listener implementation:
void OnDataMapCreation(const std::vector<uint8_t>& map_prefix,
SessionStorageDataMap* map) override;
void OnDataMapDestruction(const std::vector<uint8_t>& map_prefix) override;
void OnCommitResult(leveldb::mojom::DatabaseError error) override;
// Sets the database for testing. // Sets the database for testing.
void SetDatabaseForTesting( void SetDatabaseForTesting(
leveldb::mojom::LevelDBDatabaseAssociatedPtr database); leveldb::mojom::LevelDBDatabaseAssociatedPtr database);
...@@ -152,10 +147,20 @@ class CONTENT_EXPORT SessionStorageContextMojo ...@@ -152,10 +147,20 @@ class CONTENT_EXPORT SessionStorageContextMojo
SessionStorageMetadata::NamespaceEntry namespace_entry, SessionStorageMetadata::NamespaceEntry namespace_entry,
const url::Origin& origin); const url::Origin& origin);
// SessionStorageAreaImpl::Listener implementation:
void OnDataMapCreation(const std::vector<uint8_t>& map_prefix,
SessionStorageDataMap* map) override;
void OnDataMapDestruction(const std::vector<uint8_t>& map_prefix) override;
void OnCommitResult(leveldb::mojom::DatabaseError error) override;
// SessionStorageNamespaceImplMojo::Delegate implementation:
scoped_refptr<SessionStorageDataMap> MaybeGetExistingDataMapForId(
const std::vector<uint8_t>& map_number_as_bytes) override;
void RegisterShallowClonedNamespace( void RegisterShallowClonedNamespace(
SessionStorageMetadata::NamespaceEntry source_namespace_entry, SessionStorageMetadata::NamespaceEntry source_namespace_entry,
const std::string& new_namespace_id, const std::string& new_namespace_id,
const SessionStorageNamespaceImplMojo::OriginAreas& clone_from_areas); const SessionStorageNamespaceImplMojo::OriginAreas& clone_from_areas)
override;
std::unique_ptr<SessionStorageNamespaceImplMojo> std::unique_ptr<SessionStorageNamespaceImplMojo>
CreateSessionStorageNamespaceImplMojo(std::string namespace_id); CreateSessionStorageNamespaceImplMojo(std::string namespace_id);
......
...@@ -16,12 +16,12 @@ namespace content { ...@@ -16,12 +16,12 @@ namespace content {
SessionStorageNamespaceImplMojo::SessionStorageNamespaceImplMojo( SessionStorageNamespaceImplMojo::SessionStorageNamespaceImplMojo(
std::string namespace_id, std::string namespace_id,
SessionStorageDataMap::Listener* data_map_listener, SessionStorageDataMap::Listener* data_map_listener,
RegisterShallowClonedNamespace add_namespace_callback, SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback,
SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback) Delegate* delegate)
: namespace_id_(std::move(namespace_id)), : namespace_id_(std::move(namespace_id)),
data_map_listener_(data_map_listener), data_map_listener_(data_map_listener),
add_namespace_callback_(std::move(add_namespace_callback)), register_new_map_callback_(std::move(register_new_map_callback)),
register_new_map_callback_(std::move(register_new_map_callback)) {} delegate_(delegate) {}
SessionStorageNamespaceImplMojo::~SessionStorageNamespaceImplMojo() = default; SessionStorageNamespaceImplMojo::~SessionStorageNamespaceImplMojo() = default;
...@@ -32,22 +32,19 @@ bool SessionStorageNamespaceImplMojo::HasAreaForOrigin( ...@@ -32,22 +32,19 @@ bool SessionStorageNamespaceImplMojo::HasAreaForOrigin(
void SessionStorageNamespaceImplMojo::PopulateFromMetadata( void SessionStorageNamespaceImplMojo::PopulateFromMetadata(
leveldb::mojom::LevelDBDatabase* database, leveldb::mojom::LevelDBDatabase* database,
SessionStorageMetadata::NamespaceEntry namespace_metadata, SessionStorageMetadata::NamespaceEntry namespace_metadata) {
const std::map<std::vector<uint8_t>, SessionStorageDataMap*>&
current_data_maps) {
DCHECK(!IsPopulated()); DCHECK(!IsPopulated());
DCHECK(!waiting_on_clone_population()); DCHECK(!waiting_on_clone_population());
database_ = database; database_ = database;
populated_ = true; populated_ = true;
namespace_entry_ = namespace_metadata; namespace_entry_ = namespace_metadata;
for (const auto& pair : namespace_entry_->second) { for (const auto& pair : namespace_entry_->second) {
scoped_refptr<SessionStorageDataMap> data_map; scoped_refptr<SessionStorageDataMap> data_map =
auto map_it = current_data_maps.find(pair.second->MapNumberAsBytes()); delegate_->MaybeGetExistingDataMapForId(
if (map_it == current_data_maps.end()) { pair.second->MapNumberAsBytes());
if (!data_map) {
data_map = SessionStorageDataMap::Create(data_map_listener_, pair.second, data_map = SessionStorageDataMap::Create(data_map_listener_, pair.second,
database_); database_);
} else {
data_map = base::WrapRefCounted(map_it->second);
} }
origin_areas_[pair.first] = std::make_unique<SessionStorageAreaImpl>( origin_areas_[pair.first] = std::make_unique<SessionStorageAreaImpl>(
namespace_entry_, pair.first, std::move(data_map), namespace_entry_, pair.first, std::move(data_map),
...@@ -145,23 +142,29 @@ void SessionStorageNamespaceImplMojo::OpenArea( ...@@ -145,23 +142,29 @@ void SessionStorageNamespaceImplMojo::OpenArea(
} }
auto it = origin_areas_.find(origin); auto it = origin_areas_.find(origin);
if (it == origin_areas_.end()) { if (it == origin_areas_.end()) {
scoped_refptr<SessionStorageMetadata::MapData> map_data;
// The area may have been purged due to lack of bindings, so check the // The area may have been purged due to lack of bindings, so check the
// metadata for the map. // metadata for the map.
auto map_it = namespace_entry_->second.find(origin); scoped_refptr<SessionStorageDataMap> data_map;
if (map_it != namespace_entry_->second.end()) { auto map_data_it = namespace_entry_->second.find(origin);
map_data = map_it->second; if (map_data_it != namespace_entry_->second.end()) {
scoped_refptr<SessionStorageMetadata::MapData> map_data =
map_data_it->second;
data_map =
delegate_->MaybeGetExistingDataMapForId(map_data->MapNumberAsBytes());
if (!data_map) {
data_map = SessionStorageDataMap::Create(data_map_listener_, map_data,
database_);
}
} else { } else {
map_data = register_new_map_callback_.Run(namespace_entry_, origin); data_map = SessionStorageDataMap::Create(
data_map_listener_,
register_new_map_callback_.Run(namespace_entry_, origin), database_);
} }
it = origin_areas_ it = origin_areas_
.emplace(std::make_pair( .emplace(std::make_pair(
origin, origin, std::make_unique<SessionStorageAreaImpl>(
std::make_unique<SessionStorageAreaImpl>( namespace_entry_, origin, std::move(data_map),
namespace_entry_, origin, register_new_map_callback_)))
SessionStorageDataMap::Create(
data_map_listener_, std::move(map_data), database_),
register_new_map_callback_)))
.first; .first;
} }
it->second->Bind(std::move(database)); it->second->Bind(std::move(database));
...@@ -169,8 +172,8 @@ void SessionStorageNamespaceImplMojo::OpenArea( ...@@ -169,8 +172,8 @@ void SessionStorageNamespaceImplMojo::OpenArea(
void SessionStorageNamespaceImplMojo::Clone( void SessionStorageNamespaceImplMojo::Clone(
const std::string& clone_to_namespace) { const std::string& clone_to_namespace) {
add_namespace_callback_.Run(namespace_entry_, clone_to_namespace, delegate_->RegisterShallowClonedNamespace(namespace_entry_,
origin_areas_); clone_to_namespace, origin_areas_);
} }
void SessionStorageNamespaceImplMojo::FlushOriginForTesting( void SessionStorageNamespaceImplMojo::FlushOriginForTesting(
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#ifndef CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_NAMESPACE_IMPL_MOJO_H_ #ifndef CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_NAMESPACE_IMPL_MOJO_H_
#define CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_NAMESPACE_IMPL_MOJO_H_ #define CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_NAMESPACE_IMPL_MOJO_H_
#include <map>
#include <memory> #include <memory>
#include "base/callback.h" #include "base/callback.h"
...@@ -49,23 +50,38 @@ class CONTENT_EXPORT SessionStorageNamespaceImplMojo final ...@@ -49,23 +50,38 @@ class CONTENT_EXPORT SessionStorageNamespaceImplMojo final
public: public:
using OriginAreas = using OriginAreas =
std::map<url::Origin, std::unique_ptr<SessionStorageAreaImpl>>; std::map<url::Origin, std::unique_ptr<SessionStorageAreaImpl>>;
using RegisterShallowClonedNamespace = base::RepeatingCallback<void(
SessionStorageMetadata::NamespaceEntry source_namespace, class Delegate {
const std::string& destination_namespace, public:
const OriginAreas& areas_to_clone)>; virtual ~Delegate() = default;
// This is called when the |Clone()| method is called by mojo.
virtual void RegisterShallowClonedNamespace(
SessionStorageMetadata::NamespaceEntry source_namespace,
const std::string& destination_namespace,
const OriginAreas& areas_to_clone) = 0;
// This is called when |OpenArea()| is called. The map could have been
// purged in a call to |PurgeUnboundAreas| but the map could still be alive
// as a clone, used by another namespace.
// Returns nullptr if a data map was not found.
virtual scoped_refptr<SessionStorageDataMap> MaybeGetExistingDataMapForId(
const std::vector<uint8_t>& map_number_as_bytes) = 0;
};
// Constructs a namespace with the given |namespace_id|, expecting to be // Constructs a namespace with the given |namespace_id|, expecting to be
// populated and bound later (see class comment). The |database| and // populated and bound later (see class comment). The |database| and
// |data_map_listener| are given to any data maps constructed for this // |data_map_listener| are given to any data maps constructed for this
// namespace. The |add_namespace_callback| is called when the |Clone| method // namespace. The |delegate| is called when the |Clone| method
// is called by mojo. The |register_new_map_callback| is given to the the // is called by mojo, as well as when the |OpenArea| method is called and the
// SessionStorageAreaImpl's, used per-origin, that are bound to in // map id for that origin is found in our metadata. The
// OpenArea. // |register_new_map_callback| is given to the the SessionStorageAreaImpl's,
// used per-origin, that are bound to in OpenArea.
SessionStorageNamespaceImplMojo( SessionStorageNamespaceImplMojo(
std::string namespace_id, std::string namespace_id,
SessionStorageDataMap::Listener* data_map_listener, SessionStorageDataMap::Listener* data_map_listener,
RegisterShallowClonedNamespace add_namespace_callback, SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback,
SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback); Delegate* delegate);
~SessionStorageNamespaceImplMojo() override; ~SessionStorageNamespaceImplMojo() override;
...@@ -80,9 +96,7 @@ class CONTENT_EXPORT SessionStorageNamespaceImplMojo final ...@@ -80,9 +96,7 @@ class CONTENT_EXPORT SessionStorageNamespaceImplMojo final
// disk. Should be called before |Bind|. // disk. Should be called before |Bind|.
void PopulateFromMetadata( void PopulateFromMetadata(
leveldb::mojom::LevelDBDatabase* database, leveldb::mojom::LevelDBDatabase* database,
SessionStorageMetadata::NamespaceEntry namespace_metadata, SessionStorageMetadata::NamespaceEntry namespace_metadata);
const std::map<std::vector<uint8_t>, SessionStorageDataMap*>&
current_data_maps);
// Can either be called before |Bind|, or if the source namespace isn't // Can either be called before |Bind|, or if the source namespace isn't
// available yet, |SetWaitingForClonePopulation| can be called. Then |Bind| // available yet, |SetWaitingForClonePopulation| can be called. Then |Bind|
...@@ -137,14 +151,16 @@ class CONTENT_EXPORT SessionStorageNamespaceImplMojo final ...@@ -137,14 +151,16 @@ class CONTENT_EXPORT SessionStorageNamespaceImplMojo final
private: private:
FRIEND_TEST_ALL_PREFIXES(SessionStorageContextMojoTest, FRIEND_TEST_ALL_PREFIXES(SessionStorageContextMojoTest,
PurgeMemoryDoesNotCrashOrHang); PurgeMemoryDoesNotCrashOrHang);
FRIEND_TEST_ALL_PREFIXES(SessionStorageNamespaceImplMojoTest,
ReopenClonedAreaAfterPurge);
const std::string namespace_id_; const std::string namespace_id_;
SessionStorageMetadata::NamespaceEntry namespace_entry_; SessionStorageMetadata::NamespaceEntry namespace_entry_;
leveldb::mojom::LevelDBDatabase* database_; leveldb::mojom::LevelDBDatabase* database_ = nullptr;
SessionStorageDataMap::Listener* data_map_listener_; SessionStorageDataMap::Listener* data_map_listener_;
RegisterShallowClonedNamespace add_namespace_callback_;
SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback_; SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback_;
Delegate* delegate_;
bool waiting_on_clone_population_ = false; bool waiting_on_clone_population_ = false;
bool bind_waiting_on_clone_population_ = false; bool bind_waiting_on_clone_population_ = false;
......
...@@ -42,7 +42,9 @@ class MockListener : public SessionStorageDataMap::Listener { ...@@ -42,7 +42,9 @@ class MockListener : public SessionStorageDataMap::Listener {
MOCK_METHOD1(OnCommitResult, void(leveldb::mojom::DatabaseError error)); MOCK_METHOD1(OnCommitResult, void(leveldb::mojom::DatabaseError error));
}; };
class SessionStorageNamespaceImplMojoTest : public testing::Test { class SessionStorageNamespaceImplMojoTest
: public testing::Test,
public SessionStorageNamespaceImplMojo::Delegate {
public: public:
SessionStorageNamespaceImplMojoTest() SessionStorageNamespaceImplMojoTest()
: test_namespace_id1_(base::GenerateGUID()), : test_namespace_id1_(base::GenerateGUID()),
...@@ -100,19 +102,13 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test { ...@@ -100,19 +102,13 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test {
SessionStorageNamespaceImplMojo* CreateSessionStorageNamespaceImplMojo( SessionStorageNamespaceImplMojo* CreateSessionStorageNamespaceImplMojo(
const std::string& namespace_id) { const std::string& namespace_id) {
DCHECK(namespaces_.find(namespace_id) == namespaces_.end()); DCHECK(namespaces_.find(namespace_id) == namespaces_.end());
SessionStorageNamespaceImplMojo::RegisterShallowClonedNamespace
add_namespace_callback =
base::BindRepeating(&SessionStorageNamespaceImplMojoTest::
RegisterShallowClonedNamespace,
base::Unretained(this));
SessionStorageAreaImpl::RegisterNewAreaMap map_id_callback = SessionStorageAreaImpl::RegisterNewAreaMap map_id_callback =
base::BindRepeating( base::BindRepeating(
&SessionStorageNamespaceImplMojoTest::RegisterNewAreaMap, &SessionStorageNamespaceImplMojoTest::RegisterNewAreaMap,
base::Unretained(this)); base::Unretained(this));
auto namespace_impl = std::make_unique<SessionStorageNamespaceImplMojo>( auto namespace_impl = std::make_unique<SessionStorageNamespaceImplMojo>(
namespace_id, &listener_, std::move(add_namespace_callback), namespace_id, &listener_, std::move(map_id_callback), this);
std::move(map_id_callback));
auto* namespace_impl_ptr = namespace_impl.get(); auto* namespace_impl_ptr = namespace_impl.get();
namespaces_[namespace_id] = std::move(namespace_impl); namespaces_[namespace_id] = std::move(namespace_impl);
return namespace_impl_ptr; return namespace_impl_ptr;
...@@ -131,7 +127,8 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test { ...@@ -131,7 +127,8 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test {
void RegisterShallowClonedNamespace( void RegisterShallowClonedNamespace(
NamespaceEntry source_namespace, NamespaceEntry source_namespace,
const std::string& destination_namespace, const std::string& destination_namespace,
const SessionStorageNamespaceImplMojo::OriginAreas& areas_to_clone) { const SessionStorageNamespaceImplMojo::OriginAreas& areas_to_clone)
override {
std::vector<leveldb::mojom::BatchedOperationPtr> save_operations; std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
NamespaceEntry namespace_entry = NamespaceEntry namespace_entry =
metadata_.GetOrCreateNamespaceEntry(destination_namespace); metadata_.GetOrCreateNamespaceEntry(destination_namespace);
...@@ -150,6 +147,14 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test { ...@@ -150,6 +147,14 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test {
it->second->PopulateAsClone(&database_, namespace_entry, areas_to_clone); it->second->PopulateAsClone(&database_, namespace_entry, areas_to_clone);
} }
scoped_refptr<SessionStorageDataMap> MaybeGetExistingDataMapForId(
const std::vector<uint8_t>& map_number_as_bytes) override {
auto it = data_maps_.find(map_number_as_bytes);
if (it == data_maps_.end())
return nullptr;
return it->second;
}
protected: protected:
TestBrowserThreadBundle test_browser_thread_bundle_; TestBrowserThreadBundle test_browser_thread_bundle_;
const std::string test_namespace_id1_; const std::string test_namespace_id1_;
...@@ -162,6 +167,8 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test { ...@@ -162,6 +167,8 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test {
std::map<std::string, std::unique_ptr<SessionStorageNamespaceImplMojo>> std::map<std::string, std::unique_ptr<SessionStorageNamespaceImplMojo>>
namespaces_; namespaces_;
std::map<std::vector<uint8_t>, scoped_refptr<SessionStorageDataMap>>
data_maps_;
testing::StrictMock<MockListener> listener_; testing::StrictMock<MockListener> listener_;
std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_; std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_;
...@@ -178,8 +185,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, MetadataLoad) { ...@@ -178,8 +185,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, MetadataLoad) {
.Times(1); .Times(1);
namespace_impl->PopulateFromMetadata( namespace_impl->PopulateFromMetadata(
&database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_), &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
blink::mojom::SessionStorageNamespacePtr ss_namespace; blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1); namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
...@@ -210,8 +216,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, MetadataLoadWithMapOperations) { ...@@ -210,8 +216,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, MetadataLoadWithMapOperations) {
.Times(1); .Times(1);
namespace_impl->PopulateFromMetadata( namespace_impl->PopulateFromMetadata(
&database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_), &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
blink::mojom::SessionStorageNamespacePtr ss_namespace; blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1); namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
...@@ -250,8 +255,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, CloneBeforeBind) { ...@@ -250,8 +255,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, CloneBeforeBind) {
.Times(1); .Times(1);
namespace_impl1->PopulateFromMetadata( namespace_impl1->PopulateFromMetadata(
&database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_), &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
blink::mojom::SessionStorageNamespacePtr ss_namespace1; blink::mojom::SessionStorageNamespacePtr ss_namespace1;
namespace_impl1->Bind(mojo::MakeRequest(&ss_namespace1), namespace_impl1->Bind(mojo::MakeRequest(&ss_namespace1),
...@@ -306,8 +310,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, CloneAfterBind) { ...@@ -306,8 +310,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, CloneAfterBind) {
.Times(1); .Times(1);
namespace_impl1->PopulateFromMetadata( namespace_impl1->PopulateFromMetadata(
&database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_), &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
blink::mojom::SessionStorageNamespacePtr ss_namespace1; blink::mojom::SessionStorageNamespacePtr ss_namespace1;
namespace_impl1->Bind(mojo::MakeRequest(&ss_namespace1), namespace_impl1->Bind(mojo::MakeRequest(&ss_namespace1),
...@@ -369,8 +372,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, RemoveOriginData) { ...@@ -369,8 +372,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, RemoveOriginData) {
.Times(1); .Times(1);
namespace_impl->PopulateFromMetadata( namespace_impl->PopulateFromMetadata(
&database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_), &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
blink::mojom::SessionStorageNamespacePtr ss_namespace; blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1); namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
...@@ -416,8 +418,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, RemoveOriginDataWithoutBinding) { ...@@ -416,8 +418,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, RemoveOriginDataWithoutBinding) {
.Times(1); .Times(1);
namespace_impl->PopulateFromMetadata( namespace_impl->PopulateFromMetadata(
&database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_), &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
base::RunLoop loop; base::RunLoop loop;
EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK)) EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK))
...@@ -441,8 +442,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, ProcessLockedToOtherOrigin) { ...@@ -441,8 +442,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, ProcessLockedToOtherOrigin) {
.Times(1); .Times(1);
namespace_impl->PopulateFromMetadata( namespace_impl->PopulateFromMetadata(
&database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_), &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
blink::mojom::SessionStorageNamespacePtr ss_namespace; blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1); namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
...@@ -467,8 +467,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, PurgeUnused) { ...@@ -467,8 +467,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, PurgeUnused) {
.Times(1); .Times(1);
namespace_impl->PopulateFromMetadata( namespace_impl->PopulateFromMetadata(
&database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_), &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
blink::mojom::SessionStorageNamespacePtr ss_namespace; blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1); namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
...@@ -499,8 +498,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, NamespaceBindingPerOrigin) { ...@@ -499,8 +498,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, NamespaceBindingPerOrigin) {
.Times(1); .Times(1);
namespace_impl->PopulateFromMetadata( namespace_impl->PopulateFromMetadata(
&database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_), &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
blink::mojom::SessionStorageNamespacePtr ss_namespace_o1; blink::mojom::SessionStorageNamespacePtr ss_namespace_o1;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace_o1), namespace_impl->Bind(mojo::MakeRequest(&ss_namespace_o1),
...@@ -528,6 +526,45 @@ TEST_F(SessionStorageNamespaceImplMojoTest, NamespaceBindingPerOrigin) { ...@@ -528,6 +526,45 @@ TEST_F(SessionStorageNamespaceImplMojoTest, NamespaceBindingPerOrigin) {
.Times(1); .Times(1);
namespaces_.clear(); namespaces_.clear();
} }
} // namespace } // namespace
TEST_F(SessionStorageNamespaceImplMojoTest, ReopenClonedAreaAfterPurge) {
// Verifies that areas are kept alive after the area is unbound, and they
// are removed when PurgeUnboundWrappers() is called.
SessionStorageNamespaceImplMojo* namespace_impl =
CreateSessionStorageNamespaceImplMojo(test_namespace_id1_);
SessionStorageDataMap* data_map;
EXPECT_CALL(listener_,
OnDataMapCreation(StdStringToUint8Vector("0"), testing::_))
.WillOnce(testing::SaveArg<1>(&data_map));
namespace_impl->PopulateFromMetadata(
&database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
blink::mojom::StorageAreaAssociatedPtr leveldb_1;
ss_namespace->OpenArea(test_origin1_, mojo::MakeRequest(&leveldb_1));
// Save the data map, as if we did a clone:
data_maps_[data_map->map_data()->MapNumberAsBytes()] = data_map;
leveldb_1.reset();
namespace_impl->PurgeUnboundAreas();
EXPECT_FALSE(namespace_impl->HasAreaForOrigin(test_origin1_));
ss_namespace->OpenArea(test_origin1_, mojo::MakeRequest(&leveldb_1));
ss_namespace.FlushForTesting();
EXPECT_EQ(namespace_impl->origin_areas_[test_origin1_]->data_map(), data_map);
data_maps_.clear();
EXPECT_CALL(listener_, OnDataMapDestruction(StdStringToUint8Vector("0")))
.Times(1);
namespaces_.clear();
}
} // namespace content } // namespace content
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment