Reject additinal KEY_DELIVERY calls
Bug: b:198377119
Change-Id: I0b03115cfafa3989f4ef5bcf8660643e716d3c64
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3163792
Reviewed-by: Zach Trudo <zatrudo@google.com>
Commit-Queue: Zach Trudo <zatrudo@google.com>
Commit-Queue: Leonid Baraz <lbaraz@chromium.org>
Auto-Submit: Leonid Baraz <lbaraz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#922229}
diff --git a/components/reporting/storage/storage.cc b/components/reporting/storage/storage.cc
index c66d3bf..ace5361 100644
--- a/components/reporting/storage/storage.cc
+++ b/components/reporting/storage/storage.cc
@@ -414,9 +414,8 @@
directory_,
/*recursive=*/false, base::FileEnumerator::FILES,
base::StrCat({kEncryptionKeyFilePrefix, FILE_PATH_LITERAL("*")}));
-
- for (base::FilePath full_name = dir_enum.Next(); !full_name.empty();
- full_name = dir_enum.Next()) {
+ base::FilePath full_name;
+ while (full_name = dir_enum.Next(), !full_name.empty()) {
const auto result = key_files_to_remove.emplace(full_name);
if (!result.second) {
// Duplicate file name. Should not happen.
@@ -441,8 +440,8 @@
key_files_to_remove.erase(result.first);
}
// Delete all files assigned for deletion.
- for (const auto& full_name : key_files_to_remove) {
- base::DeleteFile(full_name); // Ignore errors, if any.
+ for (const auto& file_to_remove : key_files_to_remove) {
+ base::DeleteFile(file_to_remove); // Ignore errors, if any.
}
}
diff --git a/components/reporting/storage/storage_queue.cc b/components/reporting/storage/storage_queue.cc
index 32100d6..ea664613 100644
--- a/components/reporting/storage/storage_queue.cc
+++ b/components/reporting/storage/storage_queue.cc
@@ -241,6 +241,43 @@
return last_record_digest_;
}
+Status StorageQueue::SetGenerationId(const base::FilePath& full_name) {
+ // Data file should have generation id as an extension too.
+ // For backwards compatibility we allow it to not be included.
+ // TODO(b/195786943): Encapsulate file naming assumptions in objects.
+ const auto generation_extension =
+ full_name.RemoveFinalExtension().FinalExtension();
+ if (generation_extension.empty()) {
+ // Backwards compatibility case - extension is absent.
+ return Status::StatusOK();
+ }
+
+ int64_t file_generation_id = 0;
+ const bool success =
+ base::StringToInt64(generation_extension.substr(1), &file_generation_id);
+ if (!success || file_generation_id <= 0) {
+ return Status(error::DATA_LOSS,
+ base::StrCat({"Data file generation corrupt: '",
+ full_name.MaybeAsASCII()}));
+ }
+
+ // Found valid generation [1, int64_max] in the data file name.
+ if (generation_id_ > 0) {
+ // Generation was already set, data file must match.
+ if (file_generation_id != generation_id_) {
+ return Status(error::DATA_LOSS,
+ base::StrCat({"Data file generation does not match: '",
+ full_name.MaybeAsASCII(), "', expected=",
+ base::NumberToString(generation_id_)}));
+ }
+ } else {
+ // No generation set in the queue. Use the one from this file and expect
+ // all other files to match.
+ generation_id_ = file_generation_id;
+ }
+ return Status::StatusOK();
+}
+
StatusOr<int64_t> StorageQueue::AddDataFile(
const base::FilePath& full_name,
const base::FileEnumerator::FileInfo& file_info) {
@@ -251,38 +288,16 @@
full_name.MaybeAsASCII(), "'"}));
}
int64_t file_sequencing_id = 0;
- bool success = base::StringToInt64(extension.substr(1), &file_sequencing_id);
+ const bool success =
+ base::StringToInt64(extension.substr(1), &file_sequencing_id);
if (!success) {
return Status(error::INTERNAL,
base::StrCat({"File extension does not parse: '",
full_name.MaybeAsASCII(), "'"}));
}
- // Data file should have generation id as an extension too.
- // For backwards compatibility we allow it to not be included.
- // TODO(b/195786943): Encapsulate file naming assumptions in objects.
- const auto generation_extension =
- full_name.RemoveFinalExtension().FinalExtension();
- if (!generation_extension.empty()) {
- int64_t file_generation_id = 0;
- success = base::StringToInt64(generation_extension.substr(1),
- &file_generation_id);
- if (success && file_generation_id > 0) {
- // Found valid generation [1, int64_max] in the data file name.
- if (generation_id_ > 0) {
- // Generation was already set, data file must match.
- if (file_generation_id != generation_id_) {
- return Status(error::DATA_LOSS,
- base::StrCat({"Data file generation does not match: '",
- full_name.MaybeAsASCII(), "', expected=",
- base::NumberToString(generation_id_)}));
- }
- } else {
- // No generation set in the queue. Use the one from this file and expect
- // all other files to match.
- generation_id_ = file_generation_id;
- }
- }
- }
+
+ RETURN_IF_ERROR(SetGenerationId(full_name));
+
auto file_or_status = SingleFile::Create(full_name, file_info.GetSize());
if (!file_or_status.ok()) {
return file_or_status.status();
diff --git a/components/reporting/storage/storage_queue.h b/components/reporting/storage/storage_queue.h
index 0f57b1f..98ee016 100644
--- a/components/reporting/storage/storage_queue.h
+++ b/components/reporting/storage/storage_queue.h
@@ -219,6 +219,10 @@
const base::FilePath& full_name,
const base::FileEnumerator::FileInfo& file_info);
+ // Helper method for Init(): sets generation id based on data file name.
+ // For backwards compatibility, accepts file name without generation too.
+ Status SetGenerationId(const base::FilePath& full_name);
+
// Helper method for Init(): enumerates all data files in the directory.
// Valid file names are <prefix>.<sequencing_id>, any other names are ignored.
// Adds used data files to the set.
diff --git a/components/reporting/storage/storage_queue_unittest.cc b/components/reporting/storage/storage_queue_unittest.cc
index 56eaf024..c56ab13 100644
--- a/components/reporting/storage/storage_queue_unittest.cc
+++ b/components/reporting/storage/storage_queue_unittest.cc
@@ -555,6 +555,7 @@
StorageQueueTest* self) {
const auto status = self->set_mock_uploader_expectations_.Call(
reason, uploader.get());
+ LOG(ERROR) << "Upload reason=" << reason << " " << status;
if (!status.ok()) {
std::move(start_uploader_cb).Run(status);
return;
diff --git a/components/reporting/storage/storage_unittest.cc b/components/reporting/storage/storage_unittest.cc
index 01f48626..bfd331d 100644
--- a/components/reporting/storage/storage_unittest.cc
+++ b/components/reporting/storage/storage_unittest.cc
@@ -818,6 +818,7 @@
StorageTest* self) {
const auto status = self->set_mock_uploader_expectations_.Call(
reason, uploader.get());
+ LOG(ERROR) << "Upload reason=" << reason << " " << status;
if (!status.ok()) {
std::move(start_uploader_cb).Run(status);
return;
@@ -1011,9 +1012,14 @@
test::TestCallbackAutoWaiter waiter;
EXPECT_CALL(set_mock_uploader_expectations_,
Call(Eq(UploaderInterface::KEY_DELIVERY), NotNull()))
- .WillRepeatedly(WithArg<1>(Invoke([](TestUploader* test_uploader) {
+ // Called once with empty queue.
+ .WillOnce(WithArg<1>(Invoke([](TestUploader* test_uploader) {
TestUploader::SetEmpty uploader(test_uploader);
return Status::StatusOK();
+ })))
+ // Can be called later again, reject it.
+ .WillRepeatedly(WithArg<1>(Invoke([](TestUploader* test_uploader) {
+ return Status(error::CANCELLED, "Repeated key delivery rejected");
})));
EXPECT_CALL(set_mock_uploader_expectations_,
Call(Eq(UploaderInterface::MANUAL), NotNull()))