Index: components/safe_browsing_db/v4_store.cc |
diff --git a/components/safe_browsing_db/v4_store.cc b/components/safe_browsing_db/v4_store.cc |
index 4e731ae797c57a5929fd81b6dacd1b962487dbea..69d49a258452f55a79260ba95c1a72f3a6b98356 100644 |
--- a/components/safe_browsing_db/v4_store.cc |
+++ b/components/safe_browsing_db/v4_store.cc |
@@ -5,9 +5,11 @@ |
#include "base/base64.h" |
#include "base/bind.h" |
#include "base/files/file_util.h" |
+#include "base/memory/ptr_util.h" |
#include "base/metrics/histogram_macros.h" |
#include "base/metrics/sparse_histogram.h" |
#include "base/strings/stringprintf.h" |
+#include "components/safe_browsing_db/v4_rice.h" |
#include "components/safe_browsing_db/v4_store.h" |
#include "components/safe_browsing_db/v4_store.pb.h" |
@@ -40,6 +42,18 @@ void RecordApplyUpdateResult(ApplyUpdateResult result) { |
APPLY_UPDATE_RESULT_MAX); |
} |
+void RecordDecodeAdditionsResult(V4DecodeResult result) { |
+ UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4DecodeAdditionsResult", result, |
+ DECODE_RESULT_MAX); |
+} |
+ |
+void RecordDecodeRemovalsResult(V4DecodeResult result) { |
+ UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4DecodeRemovalsResult", result, |
+ DECODE_RESULT_MAX); |
+} |
+ |
+// TODO(vakh): Collect and record the metrics for time taken to process updates. |
+ |
void RecordApplyUpdateResultWhenReadingFromDisk(ApplyUpdateResult result) { |
UMA_HISTOGRAM_ENUMERATION( |
"SafeBrowsing.V4ApplyUpdateResultWhenReadingFromDisk", result, |
@@ -99,46 +113,81 @@ bool V4Store::Reset() { |
return true; |
} |
-void V4Store::ApplyUpdate( |
+ApplyUpdateResult V4Store::ProcessFullUpdate( |
std::unique_ptr<ListUpdateResponse> response, |
- const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, |
- UpdatedStoreReadyCallback callback) { |
- std::unique_ptr<V4Store> new_store( |
- new V4Store(this->task_runner_, this->store_path_)); |
- new_store->state_ = response->new_client_state(); |
+ const std::unique_ptr<V4Store>& new_store) { |
+ HashPrefixMap hash_prefix_map; |
+ ApplyUpdateResult apply_update_result = |
+ UpdateHashPrefixMapFromAdditions(response->additions(), &hash_prefix_map); |
+ if (apply_update_result == APPLY_UPDATE_SUCCESS) { |
+ new_store->hash_prefix_map_ = hash_prefix_map; |
+ RecordStoreWriteResult(new_store->WriteToDisk(std::move(response))); |
+ } |
+ return apply_update_result; |
+} |
+ |
+ApplyUpdateResult V4Store::ProcessPartialUpdate( |
+ std::unique_ptr<ListUpdateResponse> response, |
+ const std::unique_ptr<V4Store>& new_store) { |
// TODO(vakh): |
// 1. Done: Merge the old store and the new update in new_store. |
// 2. Create a ListUpdateResponse containing RICE encoded hash-prefixes and |
// response_type as FULL_UPDATE, and write that to disk. |
// 3. Remove this if condition after completing 1. and 2. |
- HashPrefixMap hash_prefix_map; |
- ApplyUpdateResult apply_update_result; |
- if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) { |
- const RepeatedField<int32>* raw_removals = nullptr; |
- size_t removals_size = response->removals_size(); |
- DCHECK_LE(removals_size, 1u); |
- if (removals_size == 1) { |
- const ThreatEntrySet& removal = response->removals().Get(0); |
- // TODO(vakh): Allow other compression types. |
- // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567 |
- DCHECK_EQ(RAW, removal.compression_type()); |
+ |
+ const RepeatedField<int32>* raw_removals = nullptr; |
+ RepeatedField<int32> rice_removals; |
+ size_t removals_size = response->removals_size(); |
+ DCHECK_LE(removals_size, 1u); |
+ if (removals_size == 1) { |
+ const ThreatEntrySet& removal = response->removals().Get(0); |
+ const CompressionType compression_type = removal.compression_type(); |
+ if (compression_type == RAW) { |
raw_removals = &removal.raw_indices().indices(); |
+ } else if (compression_type == RICE) { |
+ DCHECK(removal.has_rice_indices()); |
+ |
+ const RiceDeltaEncoding& rice_indices = removal.rice_indices(); |
+ V4DecodeResult decode_result = V4RiceDecoder::DecodeIntegers( |
+ rice_indices.first_value(), rice_indices.rice_parameter(), |
+ rice_indices.num_entries(), rice_indices.encoded_data(), |
+ &rice_removals); |
+ RecordDecodeRemovalsResult(decode_result); |
+ if (decode_result != DECODE_SUCCESS) { |
+ return RICE_DECODING_FAILURE; |
+ } else { |
+ raw_removals = &rice_removals; |
+ } |
+ } else { |
+ NOTREACHED() << "Unexpected compression_type type: " << compression_type; |
+ return UNEXPECTED_COMPRESSION_TYPE_REMOVALS_FAILURE; |
} |
+ } |
- apply_update_result = UpdateHashPrefixMapFromAdditions( |
- response->additions(), &hash_prefix_map); |
- if (apply_update_result == APPLY_UPDATE_SUCCESS) { |
- apply_update_result = new_store->MergeUpdate( |
- hash_prefix_map_, hash_prefix_map, raw_removals); |
- } |
- // TODO(vakh): Generate the updated ListUpdateResponse to write to disk. |
+ HashPrefixMap hash_prefix_map; |
+ ApplyUpdateResult apply_update_result = |
+ UpdateHashPrefixMapFromAdditions(response->additions(), &hash_prefix_map); |
+ |
+ if (apply_update_result == APPLY_UPDATE_SUCCESS) { |
+ apply_update_result = |
+ new_store->MergeUpdate(hash_prefix_map_, hash_prefix_map, raw_removals); |
+ } |
+ return apply_update_result; |
+} |
+ |
+void V4Store::ApplyUpdate( |
+ std::unique_ptr<ListUpdateResponse> response, |
+ const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, |
+ UpdatedStoreReadyCallback callback) { |
+ std::unique_ptr<V4Store> new_store( |
+ new V4Store(this->task_runner_, this->store_path_)); |
+ new_store->state_ = response->new_client_state(); |
+ |
+ ApplyUpdateResult apply_update_result; |
+ if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) { |
+ apply_update_result = ProcessPartialUpdate(std::move(response), new_store); |
} else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) { |
- apply_update_result = UpdateHashPrefixMapFromAdditions( |
- response->additions(), &hash_prefix_map); |
- if (apply_update_result == APPLY_UPDATE_SUCCESS) { |
- new_store->hash_prefix_map_ = hash_prefix_map; |
- RecordStoreWriteResult(new_store->WriteToDisk(std::move(response))); |
- } |
+ apply_update_result = ProcessFullUpdate(std::move(response), new_store); |
} else { |
apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE; |
NOTREACHED() << "Unexpected response type: " << response->response_type(); |
@@ -161,21 +210,46 @@ ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions( |
const RepeatedPtrField<ThreatEntrySet>& additions, |
HashPrefixMap* additions_map) { |
for (const auto& addition : additions) { |
- // TODO(vakh): Allow other compression types. |
- // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567 |
- DCHECK_EQ(RAW, addition.compression_type()); |
- |
- DCHECK(addition.has_raw_hashes()); |
- DCHECK(addition.raw_hashes().has_raw_hashes()); |
+ ApplyUpdateResult apply_update_result = APPLY_UPDATE_SUCCESS; |
+ const CompressionType compression_type = addition.compression_type(); |
+ if (compression_type == RAW) { |
+ DCHECK(addition.has_raw_hashes()); |
+ DCHECK(addition.raw_hashes().has_raw_hashes()); |
+ |
+ apply_update_result = |
+ AddUnlumpedHashes(addition.raw_hashes().prefix_size(), |
+ addition.raw_hashes().raw_hashes(), additions_map); |
+ } else if (compression_type == RICE) { |
+ DCHECK(addition.has_rice_hashes()); |
+ |
+ const RiceDeltaEncoding& rice_hashes = addition.rice_hashes(); |
+ std::string raw_hashes; |
+ V4DecodeResult decode_result = V4RiceDecoder::DecodeBytes( |
+ rice_hashes.first_value(), rice_hashes.rice_parameter(), |
+ rice_hashes.num_entries(), rice_hashes.encoded_data(), &raw_hashes); |
+ RecordDecodeAdditionsResult(decode_result); |
+ if (decode_result != DECODE_SUCCESS) { |
+ return RICE_DECODING_FAILURE; |
+ } else { |
+ // Rice-Golomb encoding is used to send compressed compressed 4-byte |
+ // hash prefixes. Hash prefixes longer than 4 bytes will not be |
+ // compressed, and will be served in raw format instead. |
+ // Source: https://developers.google.com/safe-browsing/v4/compression |
+ const PrefixSize kPrefixSize = 4; |
+ apply_update_result = |
+ AddUnlumpedHashes(kPrefixSize, raw_hashes, additions_map); |
+ } |
+ } else { |
+ NOTREACHED() << "Unexpected compression_type type: " << compression_type; |
+ return UNEXPECTED_COMPRESSION_TYPE_ADDITIONS_FAILURE; |
+ } |
- PrefixSize prefix_size = addition.raw_hashes().prefix_size(); |
- ApplyUpdateResult result = AddUnlumpedHashes( |
- prefix_size, addition.raw_hashes().raw_hashes(), additions_map); |
- if (result != APPLY_UPDATE_SUCCESS) { |
+ if (apply_update_result != APPLY_UPDATE_SUCCESS) { |
// If there was an error in updating the map, discard the update entirely. |
- return result; |
+ return apply_update_result; |
} |
} |
+ |
return APPLY_UPDATE_SUCCESS; |
} |
@@ -337,7 +411,7 @@ ApplyUpdateResult V4Store::MergeUpdate( |
return (!raw_removals || removals_iter == raw_removals->end()) |
? APPLY_UPDATE_SUCCESS |
- : REMOVALS_INDEX_TOO_LARGE; |
+ : REMOVALS_INDEX_TOO_LARGE_FAILURE; |
} |
StoreReadResult V4Store::ReadFromDisk() { |
@@ -418,7 +492,6 @@ StoreWriteResult V4Store::WriteToDisk( |
DCHECK_EQ(file_format_string.size(), written); |
if (!base::Move(new_filename, store_path_)) { |
- DVLOG(1) << "store_path_: " << store_path_.value(); |
return UNABLE_TO_RENAME_FAILURE; |
} |