Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/base64.h" | 5 #include "base/base64.h" |
| 6 #include "base/bind.h" | 6 #include "base/bind.h" |
| 7 #include "base/files/file_util.h" | 7 #include "base/files/file_util.h" |
| 8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 9 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
| 10 #include "base/metrics/sparse_histogram.h" | 10 #include "base/metrics/sparse_histogram.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
| 13 #include "components/safe_browsing_db/v4_rice.h" | 13 #include "components/safe_browsing_db/v4_rice.h" |
| 14 #include "components/safe_browsing_db/v4_store.h" | 14 #include "components/safe_browsing_db/v4_store.h" |
| 15 #include "components/safe_browsing_db/v4_store.pb.h" | 15 #include "components/safe_browsing_db/v4_store.pb.h" |
| 16 #include "crypto/secure_hash.h" | 16 #include "crypto/secure_hash.h" |
| 17 #include "crypto/sha2.h" | 17 #include "crypto/sha2.h" |
| 18 | 18 |
| 19 using base::TimeTicks; | 19 using base::TimeTicks; |
| 20 | 20 |
| 21 namespace safe_browsing { | 21 namespace safe_browsing { |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 // UMA related strings. | |
| 26 // Part 1: Represent the overall operation being performed. | |
| 27 const char kProcessFullUpdate[] = "SafeBrowsing.V4ProcessFullUpdate"; | |
| 28 const char kProcessPartialUpdate[] = "SafeBrowsing.V4ProcessPartialUpdate"; | |
| 29 const char kReadFromDisk[] = "SafeBrowsing.V4ReadFromDisk"; | |
| 30 // Part 2: Represent the sub-operation being performed as part of the larger | |
| 31 // operation from part 1. | |
| 32 const char kApplyUpdate[] = ".ApplyUpdate"; | |
| 33 const char kDecodeAdditions[] = ".DecodeAdditions"; | |
| 34 const char kDecodeRemovals[] = ".DecodeRemovals"; | |
| 35 const char kMergeUpdate[] = ".MergeUpdate"; | |
| 36 // Part 3: Represent the unit of value being measured and logged. | |
| 37 const char kResult[] = ".Result"; | |
| 38 const char kTime[] = ".Time"; | |
| 39 // UMA metric names for this file are generated by appending one value each, | |
| 40 // in order, from parts 1, 2, and 3. | |
|
Nathan Parker
2016/10/14 20:48:32
nit: You're missing part 2.5, which is the store n
vakh (use Gerrit instead)
2016/10/15 00:09:04
Done.
| |
| 41 | |
| 25 const uint32_t kFileMagic = 0x600D71FE; | 42 const uint32_t kFileMagic = 0x600D71FE; |
| 26 | |
| 27 const uint32_t kFileVersion = 9; | 43 const uint32_t kFileVersion = 9; |
| 28 | 44 |
| 29 std::string GetUmaSuffixForStore(const base::FilePath& file_path) { | 45 std::string GetUmaSuffixForStore(const base::FilePath& file_path) { |
| 30 return base::StringPrintf( | 46 return base::StringPrintf( |
| 31 ".%" PRIsFP, file_path.BaseName().RemoveExtension().value().c_str()); | 47 ".%" PRIsFP, file_path.BaseName().RemoveExtension().value().c_str()); |
| 32 } | 48 } |
| 33 | 49 |
| 34 void RecordTimeWithAndWithoutStore(const std::string& metric, | 50 void RecordTimeWithAndWithoutSuffix(const std::string& metric, |
| 35 base::TimeDelta time, | 51 base::TimeDelta time, |
| 36 const base::FilePath& file_path) { | 52 const base::FilePath& file_path) { |
| 37 // The histograms below are a modified expansion of the | 53 // The histograms below are a modified expansion of the |
| 38 // UMA_HISTOGRAM_LONG_TIMES macro adapted to allow for a dynamically suffixed | 54 // UMA_HISTOGRAM_LONG_TIMES macro adapted to allow for a dynamically suffixed |
| 39 // histogram name. | 55 // histogram name. |
| 40 // Note: The factory creates and owns the histogram. | 56 // Note: The factory creates and owns the histogram. |
| 41 const int kBucketCount = 100; | 57 const int kBucketCount = 100; |
| 42 base::HistogramBase* histogram = base::Histogram::FactoryTimeGet( | 58 base::HistogramBase* histogram = base::Histogram::FactoryTimeGet( |
| 43 metric, base::TimeDelta::FromMilliseconds(1), | 59 metric + kTime, base::TimeDelta::FromMilliseconds(1), |
| 44 base::TimeDelta::FromMinutes(1), kBucketCount, | 60 base::TimeDelta::FromMinutes(1), kBucketCount, |
| 45 base::HistogramBase::kUmaTargetedHistogramFlag); | 61 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 46 if (histogram) { | 62 if (histogram) { |
| 47 histogram->AddTime(time); | 63 histogram->AddTime(time); |
| 48 } | 64 } |
| 49 | 65 |
| 50 std::string suffix = GetUmaSuffixForStore(file_path); | 66 std::string suffix = GetUmaSuffixForStore(file_path); |
| 51 base::HistogramBase* histogram_suffix = base::Histogram::FactoryTimeGet( | 67 base::HistogramBase* histogram_suffix = base::Histogram::FactoryTimeGet( |
| 52 metric + suffix, base::TimeDelta::FromMilliseconds(1), | 68 metric + suffix + kTime, base::TimeDelta::FromMilliseconds(1), |
| 53 base::TimeDelta::FromMinutes(1), kBucketCount, | 69 base::TimeDelta::FromMinutes(1), kBucketCount, |
| 54 base::HistogramBase::kUmaTargetedHistogramFlag); | 70 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 55 if (histogram_suffix) { | 71 if (histogram_suffix) { |
| 56 histogram_suffix->AddTime(time); | 72 histogram_suffix->AddTime(time); |
| 57 } | 73 } |
| 58 } | 74 } |
| 59 | 75 |
| 76 void RecordEnumWithAndWithoutSuffix(const std::string& metric, | |
| 77 int32_t value, | |
| 78 int32_t maximum, | |
| 79 const base::FilePath& file_path) { | |
| 80 // The histograms below are an expansion of the UMA_HISTOGRAM_ENUMERATION | |
| 81 // macro adapted to allow for a dynamically suffixed histogram name. | |
| 82 // Note: The factory creates and owns the histogram. | |
| 83 base::HistogramBase* histogram = base::LinearHistogram::FactoryGet( | |
| 84 metric + kResult, 1, maximum, maximum + 1, | |
| 85 base::HistogramBase::kUmaTargetedHistogramFlag); | |
| 86 if (histogram) { | |
| 87 histogram->Add(value); | |
| 88 } | |
| 89 | |
| 90 std::string suffix = GetUmaSuffixForStore(file_path); | |
| 91 base::HistogramBase* histogram_suffix = base::LinearHistogram::FactoryGet( | |
| 92 metric + suffix + kResult, 1, maximum, maximum + 1, | |
| 93 base::HistogramBase::kUmaTargetedHistogramFlag); | |
| 94 if (histogram_suffix) { | |
| 95 histogram_suffix->Add(value); | |
| 96 } | |
| 97 } | |
| 98 | |
| 60 void RecordAddUnlumpedHashesTime(base::TimeDelta time) { | 99 void RecordAddUnlumpedHashesTime(base::TimeDelta time) { |
| 61 UMA_HISTOGRAM_LONG_TIMES("SafeBrowsing.V4AddUnlumpedHashesTime", time); | 100 UMA_HISTOGRAM_LONG_TIMES("SafeBrowsing.V4AddUnlumpedHashes.Time", time); |
| 62 } | 101 } |
| 63 | 102 |
| 64 void RecordApplyUpdateResult(ApplyUpdateResult result) { | 103 void RecordApplyUpdateResult(const std::string& base_metric, |
| 65 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4ApplyUpdateResult", result, | 104 ApplyUpdateResult result, |
| 66 APPLY_UPDATE_RESULT_MAX); | 105 const base::FilePath& file_path) { |
| 106 RecordEnumWithAndWithoutSuffix(base_metric + kApplyUpdate, result, | |
| 107 APPLY_UPDATE_RESULT_MAX, file_path); | |
| 67 } | 108 } |
| 68 | 109 |
| 69 void RecordApplyUpdateResultWhenReadingFromDisk(ApplyUpdateResult result) { | 110 void RecordApplyUpdateTime(const std::string& base_metric, |
| 70 UMA_HISTOGRAM_ENUMERATION( | 111 base::TimeDelta time, |
| 71 "SafeBrowsing.V4ApplyUpdateResultWhenReadingFromDisk", result, | 112 const base::FilePath& file_path) { |
| 72 APPLY_UPDATE_RESULT_MAX); | 113 RecordTimeWithAndWithoutSuffix(base_metric + kApplyUpdate, time, file_path); |
| 73 } | 114 } |
| 74 | 115 |
| 75 void RecordDecodeAdditionsResult(V4DecodeResult result) { | 116 void RecordDecodeAdditionsResult(const std::string& base_metric, |
| 76 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4DecodeAdditionsResult", result, | 117 V4DecodeResult result, |
| 77 DECODE_RESULT_MAX); | 118 const base::FilePath& file_path) { |
| 119 RecordEnumWithAndWithoutSuffix(base_metric + kDecodeAdditions, result, | |
| 120 DECODE_RESULT_MAX, file_path); | |
| 78 } | 121 } |
| 79 | 122 |
| 80 void RecordDecodeAdditionsTime(base::TimeDelta time, | 123 void RecordDecodeAdditionsTime(const std::string& base_metric, |
| 124 base::TimeDelta time, | |
| 81 const base::FilePath& file_path) { | 125 const base::FilePath& file_path) { |
| 82 RecordTimeWithAndWithoutStore("SafeBrowsing.V4DecodeAdditionsTime", time, | 126 RecordTimeWithAndWithoutSuffix(base_metric + kDecodeAdditions, time, |
| 83 file_path); | 127 file_path); |
| 84 } | 128 } |
| 85 | 129 |
| 86 void RecordDecodeRemovalsResult(V4DecodeResult result) { | 130 void RecordDecodeRemovalsResult(const std::string& base_metric, |
| 87 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4DecodeRemovalsResult", result, | 131 V4DecodeResult result, |
| 88 DECODE_RESULT_MAX); | 132 const base::FilePath& file_path) { |
| 133 RecordEnumWithAndWithoutSuffix(base_metric + kDecodeRemovals, result, | |
| 134 DECODE_RESULT_MAX, file_path); | |
| 89 } | 135 } |
| 90 | 136 |
| 91 void RecordDecodeRemovalsTime(base::TimeDelta time, | 137 void RecordDecodeRemovalsTime(const std::string& base_metric, |
| 138 base::TimeDelta time, | |
| 92 const base::FilePath& file_path) { | 139 const base::FilePath& file_path) { |
| 93 RecordTimeWithAndWithoutStore("SafeBrowsing.V4DecodeRemovalsTime", time, | 140 RecordTimeWithAndWithoutSuffix(base_metric + kDecodeRemovals, time, |
| 94 file_path); | 141 file_path); |
| 95 } | 142 } |
| 96 | 143 |
| 97 void RecordMergeUpdateTime(base::TimeDelta time, | 144 void RecordMergeUpdateTime(const std::string& base_metric, |
| 145 base::TimeDelta time, | |
| 98 const base::FilePath& file_path) { | 146 const base::FilePath& file_path) { |
| 99 RecordTimeWithAndWithoutStore("SafeBrowsing.V4MergeUpdateTime", time, | 147 RecordTimeWithAndWithoutSuffix(base_metric + kMergeUpdate, time, file_path); |
| 100 file_path); | |
| 101 } | |
| 102 | |
| 103 void RecordProcessFullUpdateTime(base::TimeDelta time, | |
| 104 const base::FilePath& file_path) { | |
| 105 RecordTimeWithAndWithoutStore("SafeBrowsing.V4ProcessFullUpdateTime", time, | |
| 106 file_path); | |
| 107 } | |
| 108 | |
| 109 void RecordProcessPartialUpdateTime(base::TimeDelta time, | |
| 110 const base::FilePath& file_path) { | |
| 111 RecordTimeWithAndWithoutStore("SafeBrowsing.V4ProcessPartialUpdateTime", time, | |
| 112 file_path); | |
| 113 } | |
| 114 | |
| 115 void RecordReadFromDiskTime(base::TimeDelta time, | |
| 116 const base::FilePath& file_path) { | |
| 117 RecordTimeWithAndWithoutStore("SafeBrowsing.V4ReadFromDiskTime", time, | |
| 118 file_path); | |
| 119 } | 148 } |
| 120 | 149 |
| 121 void RecordStoreReadResult(StoreReadResult result) { | 150 void RecordStoreReadResult(StoreReadResult result) { |
| 122 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreReadResult", result, | 151 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreRead.Result", result, |
| 123 STORE_READ_RESULT_MAX); | 152 STORE_READ_RESULT_MAX); |
| 124 } | 153 } |
| 125 | 154 |
| 126 void RecordStoreWriteResult(StoreWriteResult result) { | 155 void RecordStoreWriteResult(StoreWriteResult result) { |
| 127 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreWriteResult", result, | 156 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreWrite.Result", result, |
| 128 STORE_WRITE_RESULT_MAX); | 157 STORE_WRITE_RESULT_MAX); |
| 129 } | 158 } |
| 130 | 159 |
| 131 // Returns the name of the temporary file used to buffer data for | 160 // Returns the name of the temporary file used to buffer data for |
| 132 // |filename|. Exported for unit tests. | 161 // |filename|. Exported for unit tests. |
| 133 const base::FilePath TemporaryFileForFilename(const base::FilePath& filename) { | 162 const base::FilePath TemporaryFileForFilename(const base::FilePath& filename) { |
| 134 return base::FilePath(filename.value() + FILE_PATH_LITERAL("_new")); | 163 return base::FilePath(filename.value() + FILE_PATH_LITERAL("_new")); |
| 135 } | 164 } |
| 136 | 165 |
| 137 } // namespace | 166 } // namespace |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 store_path_.value().c_str(), state_base64.c_str()); | 204 store_path_.value().c_str(), state_base64.c_str()); |
| 176 } | 205 } |
| 177 | 206 |
| 178 void V4Store::Reset() { | 207 void V4Store::Reset() { |
| 179 expected_checksum_.clear(); | 208 expected_checksum_.clear(); |
| 180 hash_prefix_map_.clear(); | 209 hash_prefix_map_.clear(); |
| 181 state_ = ""; | 210 state_ = ""; |
| 182 } | 211 } |
| 183 | 212 |
| 184 ApplyUpdateResult V4Store::ProcessPartialUpdateAndWriteToDisk( | 213 ApplyUpdateResult V4Store::ProcessPartialUpdateAndWriteToDisk( |
| 214 const std::string& metric, | |
| 185 const HashPrefixMap& hash_prefix_map_old, | 215 const HashPrefixMap& hash_prefix_map_old, |
| 186 std::unique_ptr<ListUpdateResponse> response) { | 216 std::unique_ptr<ListUpdateResponse> response) { |
| 187 DCHECK(response->has_response_type()); | 217 DCHECK(response->has_response_type()); |
| 188 DCHECK_EQ(ListUpdateResponse::PARTIAL_UPDATE, response->response_type()); | 218 DCHECK_EQ(ListUpdateResponse::PARTIAL_UPDATE, response->response_type()); |
| 189 | 219 |
| 190 TimeTicks before = TimeTicks::Now(); | 220 ApplyUpdateResult result = |
| 191 ApplyUpdateResult result = ProcessUpdate(hash_prefix_map_old, response); | 221 ProcessUpdate(metric, hash_prefix_map_old, response); |
| 192 if (result == APPLY_UPDATE_SUCCESS) { | |
| 193 RecordProcessPartialUpdateTime(TimeTicks::Now() - before, store_path_); | |
| 194 // TODO(vakh): Create a ListUpdateResponse containing RICE encoded | |
| 195 // hash prefixes and response_type as FULL_UPDATE, and write that to disk. | |
| 196 } | |
| 197 return result; | 222 return result; |
| 198 } | 223 } |
| 199 | 224 |
| 200 ApplyUpdateResult V4Store::ProcessFullUpdateAndWriteToDisk( | 225 ApplyUpdateResult V4Store::ProcessFullUpdateAndWriteToDisk( |
| 226 const std::string& metric, | |
| 201 std::unique_ptr<ListUpdateResponse> response) { | 227 std::unique_ptr<ListUpdateResponse> response) { |
| 202 TimeTicks before = TimeTicks::Now(); | 228 ApplyUpdateResult result = ProcessFullUpdate(metric, response); |
| 203 ApplyUpdateResult result = ProcessFullUpdate(response); | |
| 204 if (result == APPLY_UPDATE_SUCCESS) { | 229 if (result == APPLY_UPDATE_SUCCESS) { |
| 205 RecordProcessFullUpdateTime(TimeTicks::Now() - before, store_path_); | |
| 206 RecordStoreWriteResult(WriteToDisk(std::move(response))); | 230 RecordStoreWriteResult(WriteToDisk(std::move(response))); |
| 207 } | 231 } |
| 208 return result; | 232 return result; |
| 209 } | 233 } |
| 210 | 234 |
| 211 ApplyUpdateResult V4Store::ProcessFullUpdate( | 235 ApplyUpdateResult V4Store::ProcessFullUpdate( |
| 236 const std::string& metric, | |
| 212 const std::unique_ptr<ListUpdateResponse>& response) { | 237 const std::unique_ptr<ListUpdateResponse>& response) { |
| 213 DCHECK(response->has_response_type()); | 238 DCHECK(response->has_response_type()); |
| 214 DCHECK_EQ(ListUpdateResponse::FULL_UPDATE, response->response_type()); | 239 DCHECK_EQ(ListUpdateResponse::FULL_UPDATE, response->response_type()); |
| 215 // TODO(vakh): For a full update, we don't need to process the update in | 240 // TODO(vakh): For a full update, we don't need to process the update in |
| 216 // lexographical order to store it, but we do need to do that for calculating | 241 // lexographical order to store it, but we do need to do that for calculating |
| 217 // checksum. It might save some CPU cycles to store the full update as-is and | 242 // checksum. It might save some CPU cycles to store the full update as-is and |
| 218 // walk the list of hash prefixes in lexographical order only for checksum | 243 // walk the list of hash prefixes in lexographical order only for checksum |
| 219 // calculation. | 244 // calculation. |
| 220 return ProcessUpdate(HashPrefixMap(), response); | 245 return ProcessUpdate(metric, HashPrefixMap(), response); |
| 221 } | 246 } |
| 222 | 247 |
| 223 ApplyUpdateResult V4Store::ProcessUpdate( | 248 ApplyUpdateResult V4Store::ProcessUpdate( |
| 249 const std::string& metric, | |
| 224 const HashPrefixMap& hash_prefix_map_old, | 250 const HashPrefixMap& hash_prefix_map_old, |
| 225 const std::unique_ptr<ListUpdateResponse>& response) { | 251 const std::unique_ptr<ListUpdateResponse>& response) { |
| 226 const RepeatedField<int32>* raw_removals = nullptr; | 252 const RepeatedField<int32>* raw_removals = nullptr; |
| 227 RepeatedField<int32> rice_removals; | 253 RepeatedField<int32> rice_removals; |
| 228 size_t removals_size = response->removals_size(); | 254 size_t removals_size = response->removals_size(); |
| 229 DCHECK_LE(removals_size, 1u); | 255 DCHECK_LE(removals_size, 1u); |
| 230 if (removals_size == 1) { | 256 if (removals_size == 1) { |
| 231 const ThreatEntrySet& removal = response->removals().Get(0); | 257 const ThreatEntrySet& removal = response->removals().Get(0); |
| 232 const CompressionType compression_type = removal.compression_type(); | 258 const CompressionType compression_type = removal.compression_type(); |
| 233 if (compression_type == RAW) { | 259 if (compression_type == RAW) { |
| 234 raw_removals = &removal.raw_indices().indices(); | 260 raw_removals = &removal.raw_indices().indices(); |
| 235 } else if (compression_type == RICE) { | 261 } else if (compression_type == RICE) { |
| 236 DCHECK(removal.has_rice_indices()); | 262 DCHECK(removal.has_rice_indices()); |
| 237 | 263 |
| 238 const RiceDeltaEncoding& rice_indices = removal.rice_indices(); | 264 const RiceDeltaEncoding& rice_indices = removal.rice_indices(); |
| 239 TimeTicks before = TimeTicks::Now(); | 265 TimeTicks before = TimeTicks::Now(); |
| 240 V4DecodeResult decode_result = V4RiceDecoder::DecodeIntegers( | 266 V4DecodeResult decode_result = V4RiceDecoder::DecodeIntegers( |
| 241 rice_indices.first_value(), rice_indices.rice_parameter(), | 267 rice_indices.first_value(), rice_indices.rice_parameter(), |
| 242 rice_indices.num_entries(), rice_indices.encoded_data(), | 268 rice_indices.num_entries(), rice_indices.encoded_data(), |
| 243 &rice_removals); | 269 &rice_removals); |
| 244 | 270 |
| 245 RecordDecodeRemovalsResult(decode_result); | 271 RecordDecodeRemovalsResult(metric, decode_result, store_path_); |
| 246 if (decode_result != DECODE_SUCCESS) { | 272 if (decode_result != DECODE_SUCCESS) { |
| 247 return RICE_DECODING_FAILURE; | 273 return RICE_DECODING_FAILURE; |
| 248 } | 274 } |
| 249 RecordDecodeRemovalsTime(TimeTicks::Now() - before, store_path_); | 275 RecordDecodeRemovalsTime(metric, TimeTicks::Now() - before, store_path_); |
| 250 raw_removals = &rice_removals; | 276 raw_removals = &rice_removals; |
| 251 } else { | 277 } else { |
| 252 NOTREACHED() << "Unexpected compression_type type: " << compression_type; | 278 NOTREACHED() << "Unexpected compression_type type: " << compression_type; |
| 253 return UNEXPECTED_COMPRESSION_TYPE_REMOVALS_FAILURE; | 279 return UNEXPECTED_COMPRESSION_TYPE_REMOVALS_FAILURE; |
| 254 } | 280 } |
| 255 } | 281 } |
| 256 | 282 |
| 257 HashPrefixMap hash_prefix_map; | 283 HashPrefixMap hash_prefix_map; |
| 258 ApplyUpdateResult apply_update_result = | 284 ApplyUpdateResult apply_update_result = UpdateHashPrefixMapFromAdditions( |
| 259 UpdateHashPrefixMapFromAdditions(response->additions(), &hash_prefix_map); | 285 metric, response->additions(), &hash_prefix_map); |
| 260 if (apply_update_result != APPLY_UPDATE_SUCCESS) { | 286 if (apply_update_result != APPLY_UPDATE_SUCCESS) { |
| 261 return apply_update_result; | 287 return apply_update_result; |
| 262 } | 288 } |
| 263 | 289 |
| 264 std::string expected_checksum; | 290 std::string expected_checksum; |
| 265 if (response->has_checksum() && response->checksum().has_sha256()) { | 291 if (response->has_checksum() && response->checksum().has_sha256()) { |
| 266 expected_checksum = response->checksum().sha256(); | 292 expected_checksum = response->checksum().sha256(); |
| 267 } | 293 } |
| 268 | 294 |
| 269 TimeTicks before = TimeTicks::Now(); | 295 TimeTicks before = TimeTicks::Now(); |
| 270 apply_update_result = MergeUpdate(hash_prefix_map_old, hash_prefix_map, | 296 apply_update_result = MergeUpdate(hash_prefix_map_old, hash_prefix_map, |
| 271 raw_removals, expected_checksum); | 297 raw_removals, expected_checksum); |
| 272 if (apply_update_result != APPLY_UPDATE_SUCCESS) { | 298 if (apply_update_result != APPLY_UPDATE_SUCCESS) { |
| 273 return apply_update_result; | 299 return apply_update_result; |
| 274 } | 300 } |
| 275 RecordMergeUpdateTime(TimeTicks::Now() - before, store_path_); | 301 RecordMergeUpdateTime(metric, TimeTicks::Now() - before, store_path_); |
| 276 | 302 |
| 277 state_ = response->new_client_state(); | 303 state_ = response->new_client_state(); |
| 278 return APPLY_UPDATE_SUCCESS; | 304 return APPLY_UPDATE_SUCCESS; |
| 279 } | 305 } |
| 280 | 306 |
| 281 void V4Store::ApplyUpdate( | 307 void V4Store::ApplyUpdate( |
| 282 std::unique_ptr<ListUpdateResponse> response, | 308 std::unique_ptr<ListUpdateResponse> response, |
| 283 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, | 309 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, |
| 284 UpdatedStoreReadyCallback callback) { | 310 UpdatedStoreReadyCallback callback) { |
| 285 std::unique_ptr<V4Store> new_store( | 311 std::unique_ptr<V4Store> new_store(new V4Store(task_runner_, store_path_)); |
| 286 new V4Store(this->task_runner_, this->store_path_)); | |
| 287 ApplyUpdateResult apply_update_result; | 312 ApplyUpdateResult apply_update_result; |
| 313 std::string metric; | |
| 314 TimeTicks before = TimeTicks::Now(); | |
| 288 if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) { | 315 if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) { |
| 316 metric = kProcessPartialUpdate; | |
| 289 apply_update_result = new_store->ProcessPartialUpdateAndWriteToDisk( | 317 apply_update_result = new_store->ProcessPartialUpdateAndWriteToDisk( |
| 290 hash_prefix_map_, std::move(response)); | 318 metric, hash_prefix_map_, std::move(response)); |
| 291 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) { | 319 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) { |
| 320 metric = kProcessFullUpdate; | |
| 292 apply_update_result = | 321 apply_update_result = |
| 293 new_store->ProcessFullUpdateAndWriteToDisk(std::move(response)); | 322 new_store->ProcessFullUpdateAndWriteToDisk(metric, std::move(response)); |
| 294 } else { | 323 } else { |
| 295 apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE; | 324 apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE; |
| 296 NOTREACHED() << "Failure: Unexpected response type: " | 325 NOTREACHED() << "Failure: Unexpected response type: " |
| 297 << response->response_type(); | 326 << response->response_type(); |
| 298 } | 327 } |
| 299 | 328 |
| 300 if (apply_update_result == APPLY_UPDATE_SUCCESS) { | 329 if (apply_update_result == APPLY_UPDATE_SUCCESS) { |
| 330 RecordApplyUpdateTime(metric, TimeTicks::Now() - before, store_path_); | |
| 301 // new_store is done updating, pass it to the callback. | 331 // new_store is done updating, pass it to the callback. |
| 302 callback_task_runner->PostTask( | 332 callback_task_runner->PostTask( |
| 303 FROM_HERE, base::Bind(callback, base::Passed(&new_store))); | 333 FROM_HERE, base::Bind(callback, base::Passed(&new_store))); |
| 304 } else { | 334 } else { |
| 305 DVLOG(1) << "Failure: ApplyUpdate: reason: " << apply_update_result | 335 DVLOG(1) << "Failure: ApplyUpdate: reason: " << apply_update_result |
| 306 << "; store: " << *this; | 336 << "; store: " << *this; |
| 307 // new_store failed updating. Pass a nullptr to the callback. | 337 // new_store failed updating. Pass a nullptr to the callback. |
| 308 callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr)); | 338 callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
| 309 } | 339 } |
| 310 | 340 |
| 311 RecordApplyUpdateResult(apply_update_result); | 341 RecordApplyUpdateResult(metric, apply_update_result, store_path_); |
| 312 } | 342 } |
| 313 | 343 |
| 314 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions( | 344 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions( |
| 345 const std::string& metric, | |
| 315 const RepeatedPtrField<ThreatEntrySet>& additions, | 346 const RepeatedPtrField<ThreatEntrySet>& additions, |
| 316 HashPrefixMap* additions_map) { | 347 HashPrefixMap* additions_map) { |
| 317 for (const auto& addition : additions) { | 348 for (const auto& addition : additions) { |
| 318 ApplyUpdateResult apply_update_result = APPLY_UPDATE_SUCCESS; | 349 ApplyUpdateResult apply_update_result = APPLY_UPDATE_SUCCESS; |
| 319 const CompressionType compression_type = addition.compression_type(); | 350 const CompressionType compression_type = addition.compression_type(); |
| 320 if (compression_type == RAW) { | 351 if (compression_type == RAW) { |
| 321 DCHECK(addition.has_raw_hashes()); | 352 DCHECK(addition.has_raw_hashes()); |
| 322 DCHECK(addition.raw_hashes().has_raw_hashes()); | 353 DCHECK(addition.raw_hashes().has_raw_hashes()); |
| 323 | 354 |
| 324 apply_update_result = | 355 apply_update_result = |
| 325 AddUnlumpedHashes(addition.raw_hashes().prefix_size(), | 356 AddUnlumpedHashes(addition.raw_hashes().prefix_size(), |
| 326 addition.raw_hashes().raw_hashes(), additions_map); | 357 addition.raw_hashes().raw_hashes(), additions_map); |
| 327 } else if (compression_type == RICE) { | 358 } else if (compression_type == RICE) { |
| 328 DCHECK(addition.has_rice_hashes()); | 359 DCHECK(addition.has_rice_hashes()); |
| 329 | 360 |
| 330 const RiceDeltaEncoding& rice_hashes = addition.rice_hashes(); | 361 const RiceDeltaEncoding& rice_hashes = addition.rice_hashes(); |
| 331 std::vector<uint32_t> raw_hashes; | 362 std::vector<uint32_t> raw_hashes; |
| 332 TimeTicks before = TimeTicks::Now(); | 363 TimeTicks before = TimeTicks::Now(); |
| 333 V4DecodeResult decode_result = V4RiceDecoder::DecodePrefixes( | 364 V4DecodeResult decode_result = V4RiceDecoder::DecodePrefixes( |
| 334 rice_hashes.first_value(), rice_hashes.rice_parameter(), | 365 rice_hashes.first_value(), rice_hashes.rice_parameter(), |
| 335 rice_hashes.num_entries(), rice_hashes.encoded_data(), &raw_hashes); | 366 rice_hashes.num_entries(), rice_hashes.encoded_data(), &raw_hashes); |
| 336 RecordDecodeAdditionsResult(decode_result); | 367 RecordDecodeAdditionsResult(metric, decode_result, store_path_); |
| 337 if (decode_result != DECODE_SUCCESS) { | 368 if (decode_result != DECODE_SUCCESS) { |
| 338 return RICE_DECODING_FAILURE; | 369 return RICE_DECODING_FAILURE; |
| 339 } else { | 370 } else { |
| 340 RecordDecodeAdditionsTime(TimeTicks::Now() - before, store_path_); | 371 RecordDecodeAdditionsTime(metric, TimeTicks::Now() - before, |
| 372 store_path_); | |
| 341 char* raw_hashes_start = reinterpret_cast<char*>(raw_hashes.data()); | 373 char* raw_hashes_start = reinterpret_cast<char*>(raw_hashes.data()); |
| 342 size_t raw_hashes_size = sizeof(uint32_t) * raw_hashes.size(); | 374 size_t raw_hashes_size = sizeof(uint32_t) * raw_hashes.size(); |
| 343 | 375 |
| 344 // Rice-Golomb encoding is used to send compressed compressed 4-byte | 376 // Rice-Golomb encoding is used to send compressed compressed 4-byte |
| 345 // hash prefixes. Hash prefixes longer than 4 bytes will not be | 377 // hash prefixes. Hash prefixes longer than 4 bytes will not be |
| 346 // compressed, and will be served in raw format instead. | 378 // compressed, and will be served in raw format instead. |
| 347 // Source: https://developers.google.com/safe-browsing/v4/compression | 379 // Source: https://developers.google.com/safe-browsing/v4/compression |
| 348 const PrefixSize kPrefixSize = 4; | 380 const PrefixSize kPrefixSize = 4; |
| 349 apply_update_result = AddUnlumpedHashes(kPrefixSize, raw_hashes_start, | 381 apply_update_result = AddUnlumpedHashes(kPrefixSize, raw_hashes_start, |
| 350 raw_hashes_size, additions_map); | 382 raw_hashes_size, additions_map); |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 620 if (file_format.version_number() != kFileVersion) { | 652 if (file_format.version_number() != kFileVersion) { |
| 621 return FILE_VERSION_INCOMPATIBLE_FAILURE; | 653 return FILE_VERSION_INCOMPATIBLE_FAILURE; |
| 622 } | 654 } |
| 623 | 655 |
| 624 if (!file_format.has_list_update_response()) { | 656 if (!file_format.has_list_update_response()) { |
| 625 return HASH_PREFIX_INFO_MISSING_FAILURE; | 657 return HASH_PREFIX_INFO_MISSING_FAILURE; |
| 626 } | 658 } |
| 627 | 659 |
| 628 std::unique_ptr<ListUpdateResponse> response(new ListUpdateResponse); | 660 std::unique_ptr<ListUpdateResponse> response(new ListUpdateResponse); |
| 629 response->Swap(file_format.mutable_list_update_response()); | 661 response->Swap(file_format.mutable_list_update_response()); |
| 630 ApplyUpdateResult apply_update_result = ProcessFullUpdate(response); | 662 ApplyUpdateResult apply_update_result = |
| 631 RecordApplyUpdateResultWhenReadingFromDisk(apply_update_result); | 663 ProcessFullUpdate(kReadFromDisk, response); |
| 664 RecordApplyUpdateResult(kReadFromDisk, apply_update_result, store_path_); | |
| 632 if (apply_update_result != APPLY_UPDATE_SUCCESS) { | 665 if (apply_update_result != APPLY_UPDATE_SUCCESS) { |
| 633 hash_prefix_map_.clear(); | 666 hash_prefix_map_.clear(); |
| 634 return HASH_PREFIX_MAP_GENERATION_FAILURE; | 667 return HASH_PREFIX_MAP_GENERATION_FAILURE; |
| 635 } | 668 } |
| 636 RecordReadFromDiskTime(TimeTicks::Now() - before, store_path_); | 669 RecordApplyUpdateTime(kReadFromDisk, TimeTicks::Now() - before, store_path_); |
| 637 | 670 |
| 638 return READ_SUCCESS; | 671 return READ_SUCCESS; |
| 639 } | 672 } |
| 640 | 673 |
| 641 StoreWriteResult V4Store::WriteToDisk( | 674 StoreWriteResult V4Store::WriteToDisk( |
| 642 std::unique_ptr<ListUpdateResponse> response) const { | 675 std::unique_ptr<ListUpdateResponse> response) const { |
| 643 // Do not write partial updates to the disk. | 676 // Do not write partial updates to the disk. |
| 644 // After merging the updates, the ListUpdateResponse passed to this method | 677 // After merging the updates, the ListUpdateResponse passed to this method |
| 645 // should be a FULL_UPDATE. | 678 // should be a FULL_UPDATE. |
| 646 if (!response->has_response_type() || | 679 if (!response->has_response_type() || |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 743 | 776 |
| 744 // Find the next smallest unmerged element in the map. | 777 // Find the next smallest unmerged element in the map. |
| 745 has_unmerged = GetNextSmallestUnmergedPrefix(hash_prefix_map_, iterator_map, | 778 has_unmerged = GetNextSmallestUnmergedPrefix(hash_prefix_map_, iterator_map, |
| 746 &next_smallest_prefix); | 779 &next_smallest_prefix); |
| 747 } | 780 } |
| 748 | 781 |
| 749 char checksum[crypto::kSHA256Length]; | 782 char checksum[crypto::kSHA256Length]; |
| 750 checksum_ctx->Finish(checksum, sizeof(checksum)); | 783 checksum_ctx->Finish(checksum, sizeof(checksum)); |
| 751 for (size_t i = 0; i < crypto::kSHA256Length; i++) { | 784 for (size_t i = 0; i < crypto::kSHA256Length; i++) { |
| 752 if (checksum[i] != expected_checksum_[i]) { | 785 if (checksum[i] != expected_checksum_[i]) { |
| 753 RecordApplyUpdateResultWhenReadingFromDisk(CHECKSUM_MISMATCH_FAILURE); | 786 RecordApplyUpdateResult(kReadFromDisk, CHECKSUM_MISMATCH_FAILURE, |
| 787 store_path_); | |
| 754 #if DCHECK_IS_ON() | 788 #if DCHECK_IS_ON() |
| 755 std::string checksum_b64, expected_checksum_b64; | 789 std::string checksum_b64, expected_checksum_b64; |
| 756 base::Base64Encode(base::StringPiece(checksum, arraysize(checksum)), | 790 base::Base64Encode(base::StringPiece(checksum, arraysize(checksum)), |
| 757 &checksum_b64); | 791 &checksum_b64); |
| 758 base::Base64Encode(expected_checksum_, &expected_checksum_b64); | 792 base::Base64Encode(expected_checksum_, &expected_checksum_b64); |
| 759 DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_b64 | 793 DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_b64 |
| 760 << "; expected: " << expected_checksum_b64 | 794 << "; expected: " << expected_checksum_b64 |
| 761 << "; store: " << *this; | 795 << "; store: " << *this; |
| 762 #endif | 796 #endif |
| 763 return false; | 797 return false; |
| 764 } | 798 } |
| 765 } | 799 } |
| 766 return true; | 800 return true; |
| 767 } | 801 } |
| 768 | 802 |
| 769 } // namespace safe_browsing | 803 } // namespace safe_browsing |
| OLD | NEW |