Convert IndexedDBInternalsUI to use IndexedDBControl
...instead of using IndexedDBContext. This is part of an ongoing series of changes to allow indexeddb to be moved to the storage service. As the internals ui is staying in the browser, it needs to talk to indexeddb via mojo. This change is fairly large, but mostly mechanical. Bug: 1015214 Change-Id: I3a2cd2c681ad895c11a596ce1a65fe40fe022752 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1990569 Reviewed-by: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Daniel Murphy <dmurph@chromium.org> Commit-Queue: enne <enne@chromium.org> Auto-Submit: enne <enne@chromium.org> Cr-Commit-Position: refs/heads/master@{#730857}
This commit is contained in:

committed by
Commit Bot

parent
402e678b29
commit
413e269003
components/services/storage/public/mojom
content/browser/indexed_db
@ -4,9 +4,22 @@
|
||||
|
||||
module storage.mojom;
|
||||
|
||||
import "mojo/public/mojom/base/file_path.mojom";
|
||||
import "mojo/public/mojom/base/values.mojom";
|
||||
import "mojo/public/mojom/base/time.mojom";
|
||||
import "url/mojom/origin.mojom";
|
||||
|
||||
// Recorded in histograms, so append only.
|
||||
enum ForceCloseReason {
|
||||
FORCE_CLOSE_DELETE_ORIGIN = 0,
|
||||
FORCE_CLOSE_BACKING_STORE_FAILURE = 1,
|
||||
FORCE_CLOSE_INTERNALS_PAGE = 2,
|
||||
FORCE_CLOSE_COPY_ORIGIN = 3,
|
||||
FORCE_SCHEMA_DOWNGRADE_INTERNALS_PAGE = 4,
|
||||
// Append new values here and update IDBContextForcedCloseReason in
|
||||
// enums.xml.
|
||||
};
|
||||
|
||||
// Conveys basic information about a single origin's data in IndexedDB.
|
||||
struct IndexedDBStorageUsageInfo {
|
||||
// The origin whose metadata is represented by this structure.
|
||||
@ -33,4 +46,22 @@ interface IndexedDBControl {
|
||||
|
||||
// Deletes all indexed db files for the given origin.
|
||||
DeleteForOrigin(url.mojom.Origin origin) => (bool success);
|
||||
|
||||
// Forcibly closes all connections to all databases within the origin.
|
||||
ForceClose(url.mojom.Origin origin, ForceCloseReason reason) => ();
|
||||
|
||||
// Returns the current number of connections.
|
||||
GetConnectionCount(url.mojom.Origin origin) => (uint64 connection_count);
|
||||
|
||||
// Called by chrome://indexeddb-internals to download all of the indexeddb
|
||||
// data for a particular origin. This creates a zip file at |zip_path|
|
||||
// using the temporary direction |temp_path| which needs to be cleaned up
|
||||
// after the user downloads the file.
|
||||
DownloadOriginData(url.mojom.Origin origin) => (
|
||||
bool success,
|
||||
mojo_base.mojom.FilePath temp_path,
|
||||
mojo_base.mojom.FilePath zip_path);
|
||||
|
||||
// Called by chrome://indexeddb-internals to populate its page details.
|
||||
GetAllOriginsDetails() => (bool incognito, mojo_base.mojom.ListValue details);
|
||||
};
|
||||
|
@ -256,8 +256,9 @@ class IndexedDBBackingStoreTest : public testing::Test {
|
||||
->leveldb_state()
|
||||
->RequestDestruction(loop.QuitClosure(),
|
||||
base::SequencedTaskRunnerHandle::Get());
|
||||
idb_context_->ForceClose(
|
||||
origin, IndexedDBContextImpl::FORCE_CLOSE_DELETE_ORIGIN);
|
||||
idb_context_->ForceCloseSync(
|
||||
origin,
|
||||
storage::mojom::ForceCloseReason::FORCE_CLOSE_DELETE_ORIGIN);
|
||||
loop.Run();
|
||||
}
|
||||
// All leveldb databases are closed, and they can be deleted.
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_enumerator.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "base/sequenced_task_runner.h"
|
||||
@ -39,6 +40,7 @@
|
||||
#include "storage/common/database/database_identifier.h"
|
||||
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
|
||||
#include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
|
||||
#include "third_party/zlib/google/zip.h"
|
||||
#include "ui/base/text/bytes_formatting.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
@ -53,6 +55,15 @@ const base::FilePath::CharType IndexedDBContextImpl::kIndexedDBDirectory[] =
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsAllowedPath(const std::vector<base::FilePath>& allowed_paths,
|
||||
const base::FilePath& candidate_path) {
|
||||
for (const base::FilePath& allowed_path : allowed_paths) {
|
||||
if (candidate_path == allowed_path || allowed_path.IsParent(candidate_path))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// This may be called after the IndexedDBContext is destroyed.
|
||||
void GetAllOriginsAndPaths(const base::FilePath& indexeddb_path,
|
||||
std::vector<Origin>* origins,
|
||||
@ -135,7 +146,8 @@ void IndexedDBContextImpl::GetUsage(GetUsageCallback usage_callback) {
|
||||
void IndexedDBContextImpl::DeleteForOrigin(const Origin& origin,
|
||||
DeleteForOriginCallback callback) {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
ForceClose(origin, FORCE_CLOSE_DELETE_ORIGIN);
|
||||
ForceCloseSync(origin,
|
||||
storage::mojom::ForceCloseReason::FORCE_CLOSE_DELETE_ORIGIN);
|
||||
if (!HasOrigin(origin)) {
|
||||
std::move(callback).Run(true);
|
||||
return;
|
||||
@ -163,46 +175,84 @@ void IndexedDBContextImpl::DeleteForOrigin(const Origin& origin,
|
||||
std::move(callback).Run(s.ok());
|
||||
}
|
||||
|
||||
IndexedDBFactoryImpl* IndexedDBContextImpl::GetIDBFactory() {
|
||||
void IndexedDBContextImpl::ForceClose(const Origin& origin,
|
||||
storage::mojom::ForceCloseReason reason,
|
||||
base::OnceClosure closure) {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
if (!indexeddb_factory_.get()) {
|
||||
// Prime our cache of origins with existing databases so we can
|
||||
// detect when dbs are newly created.
|
||||
GetOriginSet();
|
||||
indexeddb_factory_ = std::make_unique<IndexedDBFactoryImpl>(
|
||||
this, IndexedDBClassFactory::Get(), clock_);
|
||||
base::UmaHistogramEnumeration("WebCore.IndexedDB.Context.ForceCloseReason",
|
||||
reason);
|
||||
if (!HasOrigin(origin)) {
|
||||
std::move(closure).Run();
|
||||
return;
|
||||
}
|
||||
return indexeddb_factory_.get();
|
||||
|
||||
if (!indexeddb_factory_.get()) {
|
||||
std::move(closure).Run();
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a copy of origin, as the ref might go away here during the close.
|
||||
auto origin_copy = origin;
|
||||
indexeddb_factory_->ForceClose(
|
||||
origin_copy,
|
||||
reason == storage::mojom::ForceCloseReason::FORCE_CLOSE_DELETE_ORIGIN);
|
||||
DCHECK_EQ(0UL, GetConnectionCountSync(origin_copy));
|
||||
std::move(closure).Run();
|
||||
}
|
||||
|
||||
base::SequencedTaskRunner* IndexedDBContextImpl::IOTaskRunner() {
|
||||
DCHECK(io_task_runner_.get());
|
||||
return io_task_runner_.get();
|
||||
void IndexedDBContextImpl::GetConnectionCount(
|
||||
const Origin& origin,
|
||||
GetConnectionCountCallback callback) {
|
||||
std::move(callback).Run(GetConnectionCountSync(origin));
|
||||
}
|
||||
|
||||
std::vector<Origin> IndexedDBContextImpl::GetAllOrigins() {
|
||||
void IndexedDBContextImpl::DownloadOriginData(
|
||||
const url::Origin& origin,
|
||||
DownloadOriginDataCallback callback) {
|
||||
// All of this must run on the IndexedDB task runner to prevent script from
|
||||
// reopening the origin while we are zipping.
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
std::set<Origin>* origins_set = GetOriginSet();
|
||||
return std::vector<Origin>(origins_set->begin(), origins_set->end());
|
||||
|
||||
bool success = false;
|
||||
|
||||
// Make sure the database hasn't been deleted.
|
||||
if (!HasOrigin(origin)) {
|
||||
std::move(callback).Run(success, base::FilePath(), base::FilePath());
|
||||
return;
|
||||
}
|
||||
|
||||
ForceCloseSync(origin,
|
||||
storage::mojom::ForceCloseReason::FORCE_CLOSE_INTERNALS_PAGE);
|
||||
|
||||
base::ScopedTempDir temp_dir;
|
||||
if (!temp_dir.CreateUniqueTempDir()) {
|
||||
std::move(callback).Run(success, base::FilePath(), base::FilePath());
|
||||
return;
|
||||
}
|
||||
|
||||
// This will need to get cleaned up after the download has completed.
|
||||
base::FilePath temp_path = temp_dir.Take();
|
||||
|
||||
std::string origin_id = storage::GetIdentifierFromOrigin(origin);
|
||||
base::FilePath zip_path =
|
||||
temp_path.AppendASCII(origin_id).AddExtension(FILE_PATH_LITERAL("zip"));
|
||||
|
||||
std::vector<base::FilePath> paths = GetStoragePaths(origin);
|
||||
zip::ZipWithFilterCallback(data_path(), zip_path,
|
||||
base::BindRepeating(IsAllowedPath, paths));
|
||||
|
||||
success = true;
|
||||
std::move(callback).Run(success, temp_path, zip_path);
|
||||
}
|
||||
|
||||
bool IndexedDBContextImpl::HasOrigin(const Origin& origin) {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
std::set<Origin>* set = GetOriginSet();
|
||||
return set->find(origin) != set->end();
|
||||
}
|
||||
|
||||
static bool HostNameComparator(const Origin& i, const Origin& j) {
|
||||
return i.host() < j.host();
|
||||
}
|
||||
|
||||
base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
|
||||
void IndexedDBContextImpl::GetAllOriginsDetails(
|
||||
GetAllOriginsDetailsCallback callback) {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
std::vector<Origin> origins = GetAllOrigins();
|
||||
|
||||
std::sort(origins.begin(), origins.end(), HostNameComparator);
|
||||
std::sort(origins.begin(), origins.end());
|
||||
|
||||
std::unique_ptr<base::ListValue> list(std::make_unique<base::ListValue>());
|
||||
base::ListValue list;
|
||||
for (const auto& origin : origins) {
|
||||
std::unique_ptr<base::DictionaryValue> info(
|
||||
std::make_unique<base::DictionaryValue>());
|
||||
@ -218,14 +268,14 @@ base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
|
||||
paths->AppendString("N/A");
|
||||
}
|
||||
info->Set("paths", std::move(paths));
|
||||
info->SetDouble("connection_count", GetConnectionCount(origin));
|
||||
info->SetDouble("connection_count", GetConnectionCountSync(origin));
|
||||
|
||||
// This ends up being O(NlogN), where N = number of open databases. We
|
||||
// iterate over all open databases to extract just those in the origin, and
|
||||
// we're iterating over all origins in the outer loop.
|
||||
|
||||
if (!indexeddb_factory_.get()) {
|
||||
list->Append(std::move(info));
|
||||
list.Append(std::move(info));
|
||||
continue;
|
||||
}
|
||||
std::vector<IndexedDBDatabase*> databases =
|
||||
@ -315,9 +365,61 @@ base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
|
||||
database_list->Append(std::move(db_info));
|
||||
}
|
||||
info->Set("databases", std::move(database_list));
|
||||
list->Append(std::move(info));
|
||||
list.Append(std::move(info));
|
||||
}
|
||||
return list.release();
|
||||
|
||||
std::move(callback).Run(is_incognito(), std::move(list));
|
||||
}
|
||||
|
||||
void IndexedDBContextImpl::ForceCloseSync(
|
||||
const Origin& origin,
|
||||
storage::mojom::ForceCloseReason reason) {
|
||||
ForceClose(origin, reason, base::DoNothing());
|
||||
}
|
||||
|
||||
bool IndexedDBContextImpl::ForceSchemaDowngrade(const Origin& origin) {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
|
||||
if (is_incognito() || !HasOrigin(origin))
|
||||
return false;
|
||||
|
||||
if (indexeddb_factory_.get()) {
|
||||
indexeddb_factory_->ForceSchemaDowngrade(origin);
|
||||
return true;
|
||||
}
|
||||
ForceCloseSync(
|
||||
origin,
|
||||
storage::mojom::ForceCloseReason::FORCE_SCHEMA_DOWNGRADE_INTERNALS_PAGE);
|
||||
return false;
|
||||
}
|
||||
|
||||
IndexedDBFactoryImpl* IndexedDBContextImpl::GetIDBFactory() {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
if (!indexeddb_factory_.get()) {
|
||||
// Prime our cache of origins with existing databases so we can
|
||||
// detect when dbs are newly created.
|
||||
GetOriginSet();
|
||||
indexeddb_factory_ = std::make_unique<IndexedDBFactoryImpl>(
|
||||
this, IndexedDBClassFactory::Get(), clock_);
|
||||
}
|
||||
return indexeddb_factory_.get();
|
||||
}
|
||||
|
||||
base::SequencedTaskRunner* IndexedDBContextImpl::IOTaskRunner() {
|
||||
DCHECK(io_task_runner_.get());
|
||||
return io_task_runner_.get();
|
||||
}
|
||||
|
||||
std::vector<Origin> IndexedDBContextImpl::GetAllOrigins() {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
std::set<Origin>* origins_set = GetOriginSet();
|
||||
return std::vector<Origin>(origins_set->begin(), origins_set->end());
|
||||
}
|
||||
|
||||
bool IndexedDBContextImpl::HasOrigin(const Origin& origin) {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
std::set<Origin>* set = GetOriginSet();
|
||||
return set->find(origin) != set->end();
|
||||
}
|
||||
|
||||
int IndexedDBContextImpl::GetOriginBlobFileCount(const Origin& origin) {
|
||||
@ -368,7 +470,8 @@ void IndexedDBContextImpl::CopyOriginData(const Origin& origin,
|
||||
IndexedDBContextImpl* dest_context_impl =
|
||||
static_cast<IndexedDBContextImpl*>(dest_context);
|
||||
|
||||
ForceClose(origin, FORCE_CLOSE_COPY_ORIGIN);
|
||||
ForceCloseSync(origin,
|
||||
storage::mojom::ForceCloseReason::FORCE_CLOSE_COPY_ORIGIN);
|
||||
|
||||
// Make sure we're not about to delete our own database.
|
||||
CHECK_NE(dest_context_impl->data_path().value(), data_path().value());
|
||||
@ -389,33 +492,6 @@ void IndexedDBContextImpl::CopyOriginData(const Origin& origin,
|
||||
}
|
||||
}
|
||||
|
||||
void IndexedDBContextImpl::ForceClose(const Origin origin,
|
||||
ForceCloseReason reason) {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
base::UmaHistogramEnumeration("WebCore.IndexedDB.Context.ForceCloseReason",
|
||||
reason, FORCE_CLOSE_REASON_MAX);
|
||||
if (!HasOrigin(origin))
|
||||
return;
|
||||
|
||||
if (indexeddb_factory_.get())
|
||||
indexeddb_factory_->ForceClose(origin, reason == FORCE_CLOSE_DELETE_ORIGIN);
|
||||
DCHECK_EQ(0UL, GetConnectionCount(origin));
|
||||
}
|
||||
|
||||
bool IndexedDBContextImpl::ForceSchemaDowngrade(const Origin& origin) {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
|
||||
if (is_incognito() || !HasOrigin(origin))
|
||||
return false;
|
||||
|
||||
if (indexeddb_factory_.get()) {
|
||||
indexeddb_factory_->ForceSchemaDowngrade(origin);
|
||||
return true;
|
||||
}
|
||||
this->ForceClose(origin, FORCE_SCHEMA_DOWNGRADE_INTERNALS_PAGE);
|
||||
return false;
|
||||
}
|
||||
|
||||
V2SchemaCorruptionStatus IndexedDBContextImpl::HasV2SchemaCorruption(
|
||||
const Origin& origin) {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
@ -428,7 +504,7 @@ V2SchemaCorruptionStatus IndexedDBContextImpl::HasV2SchemaCorruption(
|
||||
return V2SchemaCorruptionStatus::kUnknown;
|
||||
}
|
||||
|
||||
size_t IndexedDBContextImpl::GetConnectionCount(const Origin& origin) {
|
||||
size_t IndexedDBContextImpl::GetConnectionCountSync(const Origin& origin) {
|
||||
DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
if (!HasOrigin(origin))
|
||||
return 0;
|
||||
|
@ -46,18 +46,6 @@ class CONTENT_EXPORT IndexedDBContextImpl
|
||||
: public IndexedDBContext,
|
||||
public storage::mojom::IndexedDBControl {
|
||||
public:
|
||||
// Recorded in histograms, so append only.
|
||||
enum ForceCloseReason {
|
||||
FORCE_CLOSE_DELETE_ORIGIN = 0,
|
||||
FORCE_CLOSE_BACKING_STORE_FAILURE,
|
||||
FORCE_CLOSE_INTERNALS_PAGE,
|
||||
FORCE_CLOSE_COPY_ORIGIN,
|
||||
FORCE_SCHEMA_DOWNGRADE_INTERNALS_PAGE,
|
||||
// Append new values here and update IDBContextForcedCloseReason in
|
||||
// enums.xml.
|
||||
FORCE_CLOSE_REASON_MAX
|
||||
};
|
||||
|
||||
class Observer {
|
||||
public:
|
||||
virtual void OnIndexedDBListChanged(const url::Origin& origin) = 0;
|
||||
@ -89,6 +77,18 @@ class CONTENT_EXPORT IndexedDBContextImpl
|
||||
void GetUsage(GetUsageCallback usage_callback) override;
|
||||
void DeleteForOrigin(const url::Origin& origin,
|
||||
DeleteForOriginCallback callback) override;
|
||||
void ForceClose(const url::Origin& origin,
|
||||
storage::mojom::ForceCloseReason reason,
|
||||
base::OnceClosure callback) override;
|
||||
void GetConnectionCount(const url::Origin& origin,
|
||||
GetConnectionCountCallback callback) override;
|
||||
void DownloadOriginData(const url::Origin& origin,
|
||||
DownloadOriginDataCallback callback) override;
|
||||
void GetAllOriginsDetails(GetAllOriginsDetailsCallback callback) override;
|
||||
|
||||
// TODO(enne): fix internal indexeddb callers to use ForceClose async instead.
|
||||
void ForceCloseSync(const url::Origin& origin,
|
||||
storage::mojom::ForceCloseReason reason);
|
||||
|
||||
IndexedDBFactoryImpl* GetIDBFactory();
|
||||
|
||||
@ -130,11 +130,6 @@ class CONTENT_EXPORT IndexedDBContextImpl
|
||||
// Used by IndexedDBInternalsUI to populate internals page.
|
||||
base::ListValue* GetAllOriginsDetails();
|
||||
|
||||
// ForceClose takes a value rather than a reference since it may release the
|
||||
// owning object.
|
||||
// ForceClose needs to move to async to support multi-thread scopes. See
|
||||
// https://crbug.com/965142.
|
||||
void ForceClose(const url::Origin origin, ForceCloseReason reason);
|
||||
bool ForceSchemaDowngrade(const url::Origin& origin);
|
||||
V2SchemaCorruptionStatus HasV2SchemaCorruption(const url::Origin& origin);
|
||||
// GetStoragePaths returns all paths owned by this database, in arbitrary
|
||||
@ -143,7 +138,7 @@ class CONTENT_EXPORT IndexedDBContextImpl
|
||||
|
||||
base::FilePath data_path() const { return data_path_; }
|
||||
bool IsInMemoryContext() const { return data_path_.empty(); }
|
||||
size_t GetConnectionCount(const url::Origin& origin);
|
||||
size_t GetConnectionCountSync(const url::Origin& origin);
|
||||
int GetOriginBlobFileCount(const url::Origin& origin);
|
||||
|
||||
// For unit tests allow to override the |data_path_|.
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "components/services/storage/indexed_db/scopes/leveldb_scopes_factory.h"
|
||||
#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.h"
|
||||
#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_factory.h"
|
||||
#include "components/services/storage/public/mojom/indexed_db_control.mojom.h"
|
||||
#include "content/browser/indexed_db/indexed_db_class_factory.h"
|
||||
#include "content/browser/indexed_db/indexed_db_connection.h"
|
||||
#include "content/browser/indexed_db/indexed_db_context_impl.h"
|
||||
@ -450,8 +451,9 @@ void IndexedDBFactoryImpl::HandleBackingStoreFailure(const Origin& origin) {
|
||||
// NULL after ContextDestroyed() called, and in some unit tests.
|
||||
if (!context_)
|
||||
return;
|
||||
context_->ForceClose(origin,
|
||||
IndexedDBContextImpl::FORCE_CLOSE_BACKING_STORE_FAILURE);
|
||||
context_->ForceCloseSync(
|
||||
origin,
|
||||
storage::mojom::ForceCloseReason::FORCE_CLOSE_BACKING_STORE_FAILURE);
|
||||
}
|
||||
|
||||
void IndexedDBFactoryImpl::HandleBackingStoreCorruption(
|
||||
|
@ -108,8 +108,9 @@ class IndexedDBFactoryTest : public testing::Test {
|
||||
->leveldb_state()
|
||||
->RequestDestruction(callback,
|
||||
base::SequencedTaskRunnerHandle::Get());
|
||||
context_->ForceClose(origin,
|
||||
IndexedDBContextImpl::FORCE_CLOSE_DELETE_ORIGIN);
|
||||
context_->ForceCloseSync(
|
||||
origin,
|
||||
storage::mojom::ForceCloseReason::FORCE_CLOSE_DELETE_ORIGIN);
|
||||
}
|
||||
loop.Run();
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "base/bind.h"
|
||||
#include "base/bind_helpers.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
@ -29,7 +28,6 @@
|
||||
#include "content/public/common/url_constants.h"
|
||||
#include "net/traffic_annotation/network_traffic_annotation.h"
|
||||
#include "storage/common/database/database_identifier.h"
|
||||
#include "third_party/zlib/google/zip.h"
|
||||
#include "ui/base/text/bytes_formatting.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
@ -37,19 +35,6 @@ using url::Origin;
|
||||
|
||||
namespace content {
|
||||
|
||||
namespace {
|
||||
|
||||
bool AllowWhitelistedPaths(const std::vector<base::FilePath>& allowed_paths,
|
||||
const base::FilePath& candidate_path) {
|
||||
for (const base::FilePath& allowed_path : allowed_paths) {
|
||||
if (candidate_path == allowed_path || allowed_path.IsParent(candidate_path))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
IndexedDBInternalsUI::IndexedDBInternalsUI(WebUI* web_ui)
|
||||
: WebUIController(web_ui) {
|
||||
web_ui->RegisterMessageCallback(
|
||||
@ -81,15 +66,6 @@ IndexedDBInternalsUI::IndexedDBInternalsUI(WebUI* web_ui)
|
||||
|
||||
IndexedDBInternalsUI::~IndexedDBInternalsUI() {}
|
||||
|
||||
void IndexedDBInternalsUI::AddContextFromStoragePartition(
|
||||
StoragePartition* partition) {
|
||||
scoped_refptr<IndexedDBContext> context = partition->GetIndexedDBContext();
|
||||
context->IDBTaskRunner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&IndexedDBInternalsUI::GetAllOriginsOnIndexedDBThread,
|
||||
base::Unretained(this), context, partition->GetPath()));
|
||||
}
|
||||
|
||||
void IndexedDBInternalsUI::GetAllOrigins(const base::ListValue* args) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
@ -98,45 +74,41 @@ void IndexedDBInternalsUI::GetAllOrigins(const base::ListValue* args) {
|
||||
|
||||
BrowserContext::ForEachStoragePartition(
|
||||
browser_context,
|
||||
base::BindRepeating(&IndexedDBInternalsUI::AddContextFromStoragePartition,
|
||||
base::Unretained(this)));
|
||||
base::BindRepeating(
|
||||
[](base::WeakPtr<IndexedDBInternalsUI> ui,
|
||||
StoragePartition* partition) {
|
||||
if (!ui)
|
||||
return;
|
||||
auto& control = partition->GetIndexedDBControl();
|
||||
control.GetAllOriginsDetails(base::BindOnce(
|
||||
[](base::WeakPtr<IndexedDBInternalsUI> ui,
|
||||
base::FilePath partition_path, bool incognito,
|
||||
base::Value info_list) {
|
||||
if (!ui)
|
||||
return;
|
||||
|
||||
ui->OnOriginsReady(
|
||||
info_list, incognito ? base::FilePath() : partition_path);
|
||||
},
|
||||
ui, partition->GetPath()));
|
||||
},
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void IndexedDBInternalsUI::GetAllOriginsOnIndexedDBThread(
|
||||
scoped_refptr<IndexedDBContext> context,
|
||||
const base::FilePath& context_path) {
|
||||
DCHECK(context->IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
|
||||
IndexedDBContextImpl* context_impl =
|
||||
static_cast<IndexedDBContextImpl*>(context.get());
|
||||
|
||||
std::unique_ptr<base::ListValue> info_list(
|
||||
context_impl->GetAllOriginsDetails());
|
||||
bool is_incognito = context_impl->is_incognito();
|
||||
|
||||
base::PostTask(
|
||||
FROM_HERE, {BrowserThread::UI},
|
||||
base::BindOnce(&IndexedDBInternalsUI::OnOriginsReady,
|
||||
base::Unretained(this), std::move(info_list),
|
||||
is_incognito ? base::FilePath() : context_path));
|
||||
}
|
||||
|
||||
void IndexedDBInternalsUI::OnOriginsReady(
|
||||
std::unique_ptr<base::ListValue> origins,
|
||||
const base::FilePath& path) {
|
||||
void IndexedDBInternalsUI::OnOriginsReady(const base::Value& origins,
|
||||
const base::FilePath& path) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
web_ui()->CallJavascriptFunctionUnsafe("indexeddb.onOriginsReady", *origins,
|
||||
web_ui()->CallJavascriptFunctionUnsafe("indexeddb.onOriginsReady", origins,
|
||||
base::Value(path.value()));
|
||||
}
|
||||
|
||||
static void FindContext(const base::FilePath& partition_path,
|
||||
static void FindControl(const base::FilePath& partition_path,
|
||||
StoragePartition** result_partition,
|
||||
scoped_refptr<IndexedDBContextImpl>* result_context,
|
||||
storage::mojom::IndexedDBControl** result_control,
|
||||
StoragePartition* storage_partition) {
|
||||
if (storage_partition->GetPath() == partition_path) {
|
||||
*result_partition = storage_partition;
|
||||
*result_context = static_cast<IndexedDBContextImpl*>(
|
||||
storage_partition->GetIndexedDBContext());
|
||||
*result_control = &storage_partition->GetIndexedDBControl();
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,7 +116,7 @@ bool IndexedDBInternalsUI::GetOriginData(
|
||||
const base::ListValue* args,
|
||||
base::FilePath* partition_path,
|
||||
Origin* origin,
|
||||
scoped_refptr<IndexedDBContextImpl>* context) {
|
||||
storage::mojom::IndexedDBControl** control) {
|
||||
base::FilePath::StringType path_string;
|
||||
if (!args->GetString(0, &path_string))
|
||||
return false;
|
||||
@ -156,23 +128,24 @@ bool IndexedDBInternalsUI::GetOriginData(
|
||||
|
||||
*origin = Origin::Create(GURL(url_string));
|
||||
|
||||
return GetOriginContext(*partition_path, *origin, context);
|
||||
return GetOriginControl(*partition_path, *origin, control);
|
||||
}
|
||||
|
||||
bool IndexedDBInternalsUI::GetOriginContext(
|
||||
bool IndexedDBInternalsUI::GetOriginControl(
|
||||
const base::FilePath& path,
|
||||
const Origin& origin,
|
||||
scoped_refptr<IndexedDBContextImpl>* context) {
|
||||
storage::mojom::IndexedDBControl** control) {
|
||||
// search the origins to find the right context
|
||||
BrowserContext* browser_context =
|
||||
web_ui()->GetWebContents()->GetBrowserContext();
|
||||
|
||||
StoragePartition* result_partition;
|
||||
StoragePartition* result_partition = nullptr;
|
||||
*control = nullptr;
|
||||
BrowserContext::ForEachStoragePartition(
|
||||
browser_context,
|
||||
base::BindRepeating(&FindContext, path, &result_partition, context));
|
||||
base::BindRepeating(&FindControl, path, &result_partition, control));
|
||||
|
||||
if (!result_partition || !(context->get()))
|
||||
if (!result_partition || !control)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -183,15 +156,38 @@ void IndexedDBInternalsUI::DownloadOriginData(const base::ListValue* args) {
|
||||
|
||||
base::FilePath partition_path;
|
||||
Origin origin;
|
||||
scoped_refptr<IndexedDBContextImpl> context;
|
||||
if (!GetOriginData(args, &partition_path, &origin, &context))
|
||||
storage::mojom::IndexedDBControl* control;
|
||||
if (!GetOriginData(args, &partition_path, &origin, &control))
|
||||
return;
|
||||
|
||||
DCHECK(context.get());
|
||||
context->IDBTaskRunner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread,
|
||||
base::Unretained(this), partition_path, context, origin));
|
||||
DCHECK(control);
|
||||
control->ForceClose(
|
||||
origin, storage::mojom::ForceCloseReason::FORCE_CLOSE_INTERNALS_PAGE,
|
||||
base::BindOnce(
|
||||
[](base::WeakPtr<IndexedDBInternalsUI> ui, Origin origin,
|
||||
base::FilePath partition_path,
|
||||
storage::mojom::IndexedDBControl* control) {
|
||||
// Is the connection count always zero after closing,
|
||||
// such that this can be simplified?
|
||||
control->GetConnectionCount(
|
||||
origin,
|
||||
base::BindOnce(
|
||||
[](base::WeakPtr<IndexedDBInternalsUI> ui, Origin origin,
|
||||
base::FilePath partition_path,
|
||||
storage::mojom::IndexedDBControl* control,
|
||||
uint64_t connection_count) {
|
||||
if (!ui)
|
||||
return;
|
||||
|
||||
control->DownloadOriginData(
|
||||
origin,
|
||||
base::BindOnce(
|
||||
&IndexedDBInternalsUI::OnDownloadDataReady, ui,
|
||||
partition_path, origin, connection_count));
|
||||
},
|
||||
ui, origin, partition_path, control));
|
||||
},
|
||||
weak_factory_.GetWeakPtr(), origin, partition_path, control));
|
||||
}
|
||||
|
||||
void IndexedDBInternalsUI::ForceCloseOrigin(const base::ListValue* args) {
|
||||
@ -199,74 +195,28 @@ void IndexedDBInternalsUI::ForceCloseOrigin(const base::ListValue* args) {
|
||||
|
||||
base::FilePath partition_path;
|
||||
Origin origin;
|
||||
scoped_refptr<IndexedDBContextImpl> context;
|
||||
if (!GetOriginData(args, &partition_path, &origin, &context))
|
||||
storage::mojom::IndexedDBControl* control;
|
||||
if (!GetOriginData(args, &partition_path, &origin, &control))
|
||||
return;
|
||||
|
||||
context->IDBTaskRunner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&IndexedDBInternalsUI::ForceCloseOriginOnIndexedDBThread,
|
||||
base::Unretained(this), partition_path, context, origin));
|
||||
}
|
||||
|
||||
void IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread(
|
||||
const base::FilePath& partition_path,
|
||||
const scoped_refptr<IndexedDBContextImpl> context,
|
||||
const Origin& origin) {
|
||||
DCHECK(context->IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
// This runs on the IndexedDB task runner to prevent script from reopening
|
||||
// the origin while we are zipping.
|
||||
|
||||
// Make sure the database hasn't been deleted since the page was loaded.
|
||||
if (!context->HasOrigin(origin))
|
||||
return;
|
||||
|
||||
context->ForceClose(origin, IndexedDBContextImpl::FORCE_CLOSE_INTERNALS_PAGE);
|
||||
size_t connection_count = context->GetConnectionCount(origin);
|
||||
|
||||
base::ScopedTempDir temp_dir;
|
||||
if (!temp_dir.CreateUniqueTempDir())
|
||||
return;
|
||||
|
||||
// This will get cleaned up after the download has completed.
|
||||
base::FilePath temp_path = temp_dir.Take();
|
||||
|
||||
std::string origin_id = storage::GetIdentifierFromOrigin(origin);
|
||||
base::FilePath zip_path =
|
||||
temp_path.AppendASCII(origin_id).AddExtension(FILE_PATH_LITERAL("zip"));
|
||||
|
||||
std::vector<base::FilePath> paths = context->GetStoragePaths(origin);
|
||||
zip::ZipWithFilterCallback(context->data_path(), zip_path,
|
||||
base::BindRepeating(AllowWhitelistedPaths, paths));
|
||||
|
||||
base::PostTask(FROM_HERE, {BrowserThread::UI},
|
||||
base::BindOnce(&IndexedDBInternalsUI::OnDownloadDataReady,
|
||||
base::Unretained(this), partition_path, origin,
|
||||
temp_path, zip_path, connection_count));
|
||||
}
|
||||
|
||||
void IndexedDBInternalsUI::ForceCloseOriginOnIndexedDBThread(
|
||||
const base::FilePath& partition_path,
|
||||
const scoped_refptr<IndexedDBContextImpl> context,
|
||||
const Origin& origin) {
|
||||
DCHECK(context->IDBTaskRunner()->RunsTasksInCurrentSequence());
|
||||
|
||||
// Make sure the database hasn't been deleted since the page was loaded.
|
||||
if (!context->HasOrigin(origin))
|
||||
return;
|
||||
|
||||
context->ForceClose(origin, IndexedDBContextImpl::FORCE_CLOSE_INTERNALS_PAGE);
|
||||
size_t connection_count = context->GetConnectionCount(origin);
|
||||
|
||||
base::PostTask(FROM_HERE, {BrowserThread::UI},
|
||||
base::BindOnce(&IndexedDBInternalsUI::OnForcedClose,
|
||||
base::Unretained(this), partition_path, origin,
|
||||
connection_count));
|
||||
control->ForceClose(
|
||||
origin, storage::mojom::ForceCloseReason::FORCE_CLOSE_INTERNALS_PAGE,
|
||||
base::BindOnce(
|
||||
[](base::WeakPtr<IndexedDBInternalsUI> ui,
|
||||
base::FilePath partition_path, Origin origin,
|
||||
storage::mojom::IndexedDBControl* control) {
|
||||
if (!ui)
|
||||
return;
|
||||
control->GetConnectionCount(
|
||||
origin, base::BindOnce(&IndexedDBInternalsUI::OnForcedClose, ui,
|
||||
partition_path, origin));
|
||||
},
|
||||
weak_factory_.GetWeakPtr(), partition_path, origin, control));
|
||||
}
|
||||
|
||||
void IndexedDBInternalsUI::OnForcedClose(const base::FilePath& partition_path,
|
||||
const Origin& origin,
|
||||
size_t connection_count) {
|
||||
uint64_t connection_count) {
|
||||
web_ui()->CallJavascriptFunctionUnsafe(
|
||||
"indexeddb.onForcedClose", base::Value(partition_path.value()),
|
||||
base::Value(origin.Serialize()),
|
||||
@ -276,10 +226,14 @@ void IndexedDBInternalsUI::OnForcedClose(const base::FilePath& partition_path,
|
||||
void IndexedDBInternalsUI::OnDownloadDataReady(
|
||||
const base::FilePath& partition_path,
|
||||
const Origin& origin,
|
||||
const base::FilePath temp_path,
|
||||
const base::FilePath zip_path,
|
||||
size_t connection_count) {
|
||||
uint64_t connection_count,
|
||||
bool success,
|
||||
const base::FilePath& temp_path,
|
||||
const base::FilePath& zip_path) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
const GURL url = GURL(FILE_PATH_LITERAL("file://") + zip_path.value());
|
||||
WebContents* web_contents = web_ui()->GetWebContents();
|
||||
net::NetworkTrafficAnnotationTag traffic_annotation =
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "components/download/public/common/download_interrupt_reasons.h"
|
||||
#include "components/services/storage/public/mojom/indexed_db_control.mojom.h"
|
||||
#include "content/public/browser/indexed_db_context.h"
|
||||
#include "content/public/browser/web_ui_controller.h"
|
||||
|
||||
@ -30,9 +31,6 @@ class DownloadItem;
|
||||
|
||||
namespace content {
|
||||
|
||||
class IndexedDBContextImpl;
|
||||
class StoragePartition;
|
||||
|
||||
// The implementation for the chrome://indexeddb-internals page.
|
||||
class IndexedDBInternalsUI : public WebUIController {
|
||||
public:
|
||||
@ -41,23 +39,15 @@ class IndexedDBInternalsUI : public WebUIController {
|
||||
|
||||
private:
|
||||
void GetAllOrigins(const base::ListValue* args);
|
||||
void GetAllOriginsOnIndexedDBThread(scoped_refptr<IndexedDBContext> context,
|
||||
const base::FilePath& context_path);
|
||||
void OnOriginsReady(std::unique_ptr<base::ListValue> origins,
|
||||
const base::FilePath& path);
|
||||
|
||||
void AddContextFromStoragePartition(StoragePartition* partition);
|
||||
void OnOriginsReady(const base::Value& origins, const base::FilePath& path);
|
||||
|
||||
void DownloadOriginData(const base::ListValue* args);
|
||||
void DownloadOriginDataOnIndexedDBThread(
|
||||
const base::FilePath& partition_path,
|
||||
const scoped_refptr<IndexedDBContextImpl> context,
|
||||
const url::Origin& origin);
|
||||
void OnDownloadDataReady(const base::FilePath& partition_path,
|
||||
const url::Origin& origin,
|
||||
const base::FilePath temp_path,
|
||||
const base::FilePath zip_path,
|
||||
size_t connection_count);
|
||||
uint64_t connection_count,
|
||||
bool success,
|
||||
const base::FilePath& temp_path,
|
||||
const base::FilePath& zip_path);
|
||||
void OnDownloadStarted(const base::FilePath& partition_path,
|
||||
const url::Origin& origin,
|
||||
const base::FilePath& temp_path,
|
||||
@ -66,22 +56,19 @@ class IndexedDBInternalsUI : public WebUIController {
|
||||
download::DownloadInterruptReason interrupt_reason);
|
||||
|
||||
void ForceCloseOrigin(const base::ListValue* args);
|
||||
void ForceCloseOriginOnIndexedDBThread(
|
||||
const base::FilePath& partition_path,
|
||||
const scoped_refptr<IndexedDBContextImpl> context,
|
||||
const url::Origin& origin);
|
||||
void OnForcedClose(const base::FilePath& partition_path,
|
||||
const url::Origin& origin,
|
||||
size_t connection_count);
|
||||
uint64_t connection_count);
|
||||
|
||||
bool GetOriginContext(const base::FilePath& path,
|
||||
bool GetOriginControl(const base::FilePath& path,
|
||||
const url::Origin& origin,
|
||||
scoped_refptr<IndexedDBContextImpl>* context);
|
||||
storage::mojom::IndexedDBControl** control);
|
||||
bool GetOriginData(const base::ListValue* args,
|
||||
base::FilePath* path,
|
||||
url::Origin* origin,
|
||||
scoped_refptr<IndexedDBContextImpl>* context);
|
||||
storage::mojom::IndexedDBControl** control);
|
||||
|
||||
base::WeakPtrFactory<IndexedDBInternalsUI> weak_factory_{this};
|
||||
DISALLOW_COPY_AND_ASSIGN(IndexedDBInternalsUI);
|
||||
};
|
||||
|
||||
|
@ -142,8 +142,9 @@ class IndexedDBTest : public testing::Test {
|
||||
->leveldb_state()
|
||||
->RequestDestruction(callback,
|
||||
base::SequencedTaskRunnerHandle::Get());
|
||||
context_->ForceClose(origin,
|
||||
IndexedDBContextImpl::FORCE_CLOSE_DELETE_ORIGIN);
|
||||
context_->ForceCloseSync(
|
||||
origin,
|
||||
storage::mojom::ForceCloseReason::FORCE_CLOSE_DELETE_ORIGIN);
|
||||
}
|
||||
loop.Run();
|
||||
}
|
||||
@ -285,8 +286,8 @@ TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnDelete) {
|
||||
IndexedDBConnection::CloseErrorHandling::kAbortAllReturnLastError);
|
||||
RunPostedTasks();
|
||||
|
||||
context()->ForceClose(kTestOrigin,
|
||||
IndexedDBContextImpl::FORCE_CLOSE_DELETE_ORIGIN);
|
||||
context()->ForceCloseSync(
|
||||
kTestOrigin, storage::mojom::ForceCloseReason::FORCE_CLOSE_DELETE_ORIGIN);
|
||||
EXPECT_TRUE(open_db_callbacks->forced_close_called());
|
||||
EXPECT_FALSE(closed_db_callbacks->forced_close_called());
|
||||
|
||||
|
Reference in New Issue
Block a user