Commit 5e2ff0e9 authored by Rayan Kanso's avatar Rayan Kanso Committed by Commit Bot

[ContentIndex] Handle corrupted data in DB operations.

Bug: 973844
Change-Id: I5e71e72cb91a3e87c0f6dc7f21d45bc686c4fd77
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1782564Reviewed-by: default avatarRichard Knoll <knollr@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarIlya Sherman <isherman@chromium.org>
Commit-Queue: Rayan Kanso <rayankans@chromium.org>
Cr-Commit-Position: refs/heads/master@{#693096}
parent ae1f8501
...@@ -4,10 +4,12 @@ ...@@ -4,10 +4,12 @@
#include "content/browser/content_index/content_index_database.h" #include "content/browser/content_index/content_index_database.h"
#include <set>
#include <string> #include <string>
#include "base/barrier_closure.h" #include "base/barrier_closure.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/stl_util.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "content/browser/background_fetch/storage/image_helpers.h" #include "content/browser/background_fetch/storage/image_helpers.h"
...@@ -334,10 +336,12 @@ void ContentIndexDatabase::GetDescriptionsOnCoreThread( ...@@ -334,10 +336,12 @@ void ContentIndexDatabase::GetDescriptionsOnCoreThread(
service_worker_context_->GetRegistrationUserDataByKeyPrefix( service_worker_context_->GetRegistrationUserDataByKeyPrefix(
service_worker_registration_id, kEntryPrefix, service_worker_registration_id, kEntryPrefix,
base::BindOnce(&ContentIndexDatabase::DidGetDescriptions, base::BindOnce(&ContentIndexDatabase::DidGetDescriptions,
weak_ptr_factory_core_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, std::move(callback)));
} }
void ContentIndexDatabase::DidGetDescriptions( void ContentIndexDatabase::DidGetDescriptions(
int64_t service_worker_registration_id,
blink::mojom::ContentIndexService::GetDescriptionsCallback callback, blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
const std::vector<std::string>& data, const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) { blink::ServiceWorkerStatusCode status) {
...@@ -356,10 +360,10 @@ void ContentIndexDatabase::DidGetDescriptions( ...@@ -356,10 +360,10 @@ void ContentIndexDatabase::DidGetDescriptions(
std::vector<blink::mojom::ContentDescriptionPtr> descriptions; std::vector<blink::mojom::ContentDescriptionPtr> descriptions;
descriptions.reserve(data.size()); descriptions.reserve(data.size());
// TODO(crbug.com/973844): Clear the storage if there is data corruption.
for (const auto& serialized_entry : data) { for (const auto& serialized_entry : data) {
proto::ContentEntry entry; proto::ContentEntry entry;
if (!entry.ParseFromString(serialized_entry)) { if (!entry.ParseFromString(serialized_entry)) {
ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR, std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
/* descriptions= */ {}); /* descriptions= */ {});
return; return;
...@@ -367,9 +371,14 @@ void ContentIndexDatabase::DidGetDescriptions( ...@@ -367,9 +371,14 @@ void ContentIndexDatabase::DidGetDescriptions(
auto description = DescriptionFromProto(entry.description()); auto description = DescriptionFromProto(entry.description());
if (!description) { if (!description) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR, // Clear entry data.
/* descriptions= */ {}); service_worker_context_->ClearRegistrationUserData(
return; service_worker_registration_id,
{EntryKey(entry.description().id()),
IconsKey(entry.description().id())},
base::BindOnce(&content_index::RecordDatabaseOperationStatus,
"ClearCorruptedData"));
continue;
} }
descriptions.push_back(std::move(description)); descriptions.push_back(std::move(description));
...@@ -410,10 +419,12 @@ void ContentIndexDatabase::GetIconsOnCoreThread( ...@@ -410,10 +419,12 @@ void ContentIndexDatabase::GetIconsOnCoreThread(
service_worker_context_->GetRegistrationUserData( service_worker_context_->GetRegistrationUserData(
service_worker_registration_id, {IconsKey(description_id)}, service_worker_registration_id, {IconsKey(description_id)},
base::BindOnce(&ContentIndexDatabase::DidGetSerializedIcons, base::BindOnce(&ContentIndexDatabase::DidGetSerializedIcons,
weak_ptr_factory_core_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, std::move(callback)));
} }
void ContentIndexDatabase::DidGetSerializedIcons( void ContentIndexDatabase::DidGetSerializedIcons(
int64_t service_worker_registration_id,
ContentIndexContext::GetIconsCallback callback, ContentIndexContext::GetIconsCallback callback,
const std::vector<std::string>& data, const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) { blink::ServiceWorkerStatusCode status) {
...@@ -429,7 +440,7 @@ void ContentIndexDatabase::DidGetSerializedIcons( ...@@ -429,7 +440,7 @@ void ContentIndexDatabase::DidGetSerializedIcons(
DCHECK_EQ(data.size(), 1u); DCHECK_EQ(data.size(), 1u);
proto::SerializedIcons serialized_icons; proto::SerializedIcons serialized_icons;
if (!serialized_icons.ParseFromString(data.front())) { if (!serialized_icons.ParseFromString(data.front())) {
// TODO(crbug.com/973844): Clear the storage if there is data corruption. ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
std::move(callback).Run({}); std::move(callback).Run({});
return; return;
} }
...@@ -521,19 +532,28 @@ void ContentIndexDatabase::DidGetEntries( ...@@ -521,19 +532,28 @@ void ContentIndexDatabase::DidGetEntries(
std::vector<ContentIndexEntry> entries; std::vector<ContentIndexEntry> entries;
entries.reserve(user_data.size()); entries.reserve(user_data.size());
std::set<int64_t> corrupted_sw_ids;
for (const auto& ud : user_data) { for (const auto& ud : user_data) {
auto entry = EntryFromSerializedProto(ud.first, ud.second); auto entry = EntryFromSerializedProto(ud.first, ud.second);
// TODO(crbug.com/973844): Clear the storage if there is data corruption.
if (!entry) { if (!entry) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR, corrupted_sw_ids.insert(ud.first);
/* entries= */ {}); continue;
return;
} }
entries.emplace_back(std::move(*entry)); entries.emplace_back(std::move(*entry));
} }
if (!corrupted_sw_ids.empty()) {
// Remove soon-to-be-deleted entries.
base::EraseIf(entries, [&corrupted_sw_ids](const auto& entry) {
return corrupted_sw_ids.count(entry.service_worker_registration_id);
});
for (int64_t service_worker_registration_id : corrupted_sw_ids)
ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
}
std::move(callback).Run(blink::mojom::ContentIndexError::NONE, std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
std::move(entries)); std::move(entries));
} }
...@@ -590,6 +610,16 @@ void ContentIndexDatabase::DidGetEntry( ...@@ -590,6 +610,16 @@ void ContentIndexDatabase::DidGetEntry(
EntryFromSerializedProto(service_worker_registration_id, data.front())); EntryFromSerializedProto(service_worker_registration_id, data.front()));
} }
void ContentIndexDatabase::ClearServiceWorkerDataOnCorruption(
int64_t service_worker_registration_id) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
service_worker_context_->ClearRegistrationUserDataByKeyPrefixes(
service_worker_registration_id, {kEntryPrefix, kIconPrefix},
base::BindOnce(&content_index::RecordDatabaseOperationStatus,
"ClearCorruptedData"));
}
void ContentIndexDatabase::DeleteItem(int64_t service_worker_registration_id, void ContentIndexDatabase::DeleteItem(int64_t service_worker_registration_id,
const url::Origin& origin, const url::Origin& origin,
const std::string& description_id) { const std::string& description_id) {
......
...@@ -127,12 +127,14 @@ class CONTENT_EXPORT ContentIndexDatabase { ...@@ -127,12 +127,14 @@ class CONTENT_EXPORT ContentIndexDatabase {
// GetDescriptions Callbacks. // GetDescriptions Callbacks.
void DidGetDescriptions( void DidGetDescriptions(
int64_t service_worker_registration_id,
blink::mojom::ContentIndexService::GetDescriptionsCallback callback, blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
const std::vector<std::string>& data, const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status); blink::ServiceWorkerStatusCode status);
// GetIcons Callbacks. // GetIcons Callbacks.
void DidGetSerializedIcons(ContentIndexContext::GetIconsCallback callback, void DidGetSerializedIcons(int64_t service_worker_registration_id,
ContentIndexContext::GetIconsCallback callback,
const std::vector<std::string>& data, const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status); blink::ServiceWorkerStatusCode status);
void DidDeserializeIcons(ContentIndexContext::GetIconsCallback callback, void DidDeserializeIcons(ContentIndexContext::GetIconsCallback callback,
...@@ -167,6 +169,10 @@ class CONTENT_EXPORT ContentIndexDatabase { ...@@ -167,6 +169,10 @@ class CONTENT_EXPORT ContentIndexDatabase {
void DidDispatchEvent(const url::Origin& origin, void DidDispatchEvent(const url::Origin& origin,
blink::ServiceWorkerStatusCode service_worker_status); blink::ServiceWorkerStatusCode service_worker_status);
// Clears all the content index related data in a service worker.
void ClearServiceWorkerDataOnCorruption(
int64_t service_worker_registration_id);
// Callbacks on the UI thread to notify |provider_| of updates. // Callbacks on the UI thread to notify |provider_| of updates.
void NotifyProviderContentAdded(std::vector<ContentIndexEntry> entries); void NotifyProviderContentAdded(std::vector<ContentIndexEntry> entries);
void NotifyProviderContentDeleted(int64_t service_worker_registration_id, void NotifyProviderContentDeleted(int64_t service_worker_registration_id,
......
...@@ -18,6 +18,14 @@ ContentIndexEntry::ContentIndexEntry( ...@@ -18,6 +18,14 @@ ContentIndexEntry::ContentIndexEntry(
ContentIndexEntry::ContentIndexEntry(ContentIndexEntry&& other) = default; ContentIndexEntry::ContentIndexEntry(ContentIndexEntry&& other) = default;
ContentIndexEntry& ContentIndexEntry::operator=(ContentIndexEntry&& other) {
service_worker_registration_id = other.service_worker_registration_id;
description = std::move(other.description);
launch_url = std::move(other.launch_url);
registration_time = other.registration_time;
return *this;
}
ContentIndexEntry::~ContentIndexEntry() = default; ContentIndexEntry::~ContentIndexEntry() = default;
ContentIndexProvider::ContentIndexProvider() = default; ContentIndexProvider::ContentIndexProvider() = default;
......
...@@ -29,6 +29,7 @@ struct CONTENT_EXPORT ContentIndexEntry { ...@@ -29,6 +29,7 @@ struct CONTENT_EXPORT ContentIndexEntry {
const GURL& launch_url, const GURL& launch_url,
base::Time registration_time); base::Time registration_time);
ContentIndexEntry(ContentIndexEntry&& other); ContentIndexEntry(ContentIndexEntry&& other);
ContentIndexEntry& operator=(ContentIndexEntry&& other);
~ContentIndexEntry(); ~ContentIndexEntry();
// Part of the key for an entry since different service workers can use the // Part of the key for an entry since different service workers can use the
......
...@@ -161368,6 +161368,7 @@ regressions. --> ...@@ -161368,6 +161368,7 @@ regressions. -->
<histogram_suffixes name="ContentIndexDatabaseTask" separator="."> <histogram_suffixes name="ContentIndexDatabaseTask" separator=".">
<suffix name="Add" label="Register content"/> <suffix name="Add" label="Register content"/>
<suffix name="ClearCorruptedData" label="Clear data in SW"/>
<suffix name="Delete" label="Delete content"/> <suffix name="Delete" label="Delete content"/>
<suffix name="GetAllEntries" label="Get all entries"/> <suffix name="GetAllEntries" label="Get all entries"/>
<suffix name="GetDescriptions" label="Get registered content"/> <suffix name="GetDescriptions" label="Get registered 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