blob: bc1f2c50359c2e48724112cb93742deecdec6a87 [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 <memory>
#include <vector>
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "content/browser/dom_storage/session_storage_metadata.h"
#include "content/browser/dom_storage/storage_area_impl.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
namespace content {
// Holds the StorageArea for a session storage data map. Every
// namespace-origin area has a data map. To support shallow copying of the data
// (copy-on-write), a single data map can be shared between multiple namespaces.
// Thus this class is refcounted. This class has a one-to-one relationship with
// the SessionStorageMetadata::MapData object, accessible from |map_data()|.
// Neither this data map nor the inner StorageArea is bound to, as it needs
// to be shared between multiple connections if it is shallow-copied. However,
// it does allow it's user to keep track of the number of binding using
// |binding_count()|, |AddBindingReference()|, and |RemoveBindingReference()|.
class CONTENT_EXPORT SessionStorageDataMap final
: public StorageAreaImpl::Delegate,
public base::RefCounted<SessionStorageDataMap> {
class CONTENT_EXPORT Listener {
virtual ~Listener() {}
virtual void OnDataMapCreation(const std::vector<uint8_t>& map_id,
SessionStorageDataMap* map) = 0;
virtual void OnDataMapDestruction(const std::vector<uint8_t>& map_id) = 0;
virtual void OnCommitResult(leveldb::mojom::DatabaseError error) = 0;
static scoped_refptr<SessionStorageDataMap> CreateFromDisk(
Listener* listener,
scoped_refptr<SessionStorageMetadata::MapData> map_data,
leveldb::mojom::LevelDBDatabase* database);
static scoped_refptr<SessionStorageDataMap> CreateEmpty(
Listener* listener,
scoped_refptr<SessionStorageMetadata::MapData> map_data,
leveldb::mojom::LevelDBDatabase* database);
static scoped_refptr<SessionStorageDataMap> CreateClone(
Listener* listener,
scoped_refptr<SessionStorageMetadata::MapData> map_data,
scoped_refptr<SessionStorageDataMap> clone_from);
Listener* listener() const { return listener_; }
StorageAreaImpl* storage_area() { return storage_area_ptr_; }
scoped_refptr<SessionStorageMetadata::MapData> map_data() {
return map_data_.get();
int binding_count() { return binding_count_; }
void AddBindingReference() { ++binding_count_; }
// When the binding count reaches 0, we schedule an immediate commit on our
// area, but we don't close the connection.
void RemoveBindingReference();
// Note: this is irrelevant, as the parent area is handling binding.
void OnNoBindings() override {}
std::vector<leveldb::mojom::BatchedOperationPtr> PrepareToCommit() override;
void DidCommit(leveldb::mojom::DatabaseError error) override;
friend class base::RefCounted<SessionStorageDataMap>;
Listener* listener,
scoped_refptr<SessionStorageMetadata::MapData> map_entry,
leveldb::mojom::LevelDBDatabase* database,
bool is_empty);
Listener* listener,
scoped_refptr<SessionStorageMetadata::MapData> map_entry,
scoped_refptr<SessionStorageDataMap> forking_from);
~SessionStorageDataMap() override;
void OnMapLoaded(leveldb::mojom::DatabaseError error) override;
static StorageAreaImpl::Options GetOptions();
Listener* listener_;
int binding_count_ = 0;
// If we're cloning from another map, we need to keep it alive while it forks.
// Note, this has to be above the storage_area_impl_ in case the Fork call
// completes synchronously.
scoped_refptr<SessionStorageDataMap> clone_from_data_map_;
scoped_refptr<SessionStorageMetadata::MapData> map_data_;
std::unique_ptr<StorageAreaImpl> storage_area_impl_;
// Holds the same value as |storage_area_impl_|. The reason for this is that
// during destruction of the StorageAreaImpl instance we might still get
// called and need access to the StorageAreaImpl instance. The
// unique_ptr could already be null, but this field should still be valid.
// TODO(dmurph): Change delegate ownership so this doesn't have to be done.
StorageAreaImpl* storage_area_ptr_;
} // namespace content