| 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" |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 using ::google::protobuf::int32; | 174 using ::google::protobuf::int32; |
| 175 | 175 |
| 176 std::ostream& operator<<(std::ostream& os, const V4Store& store) { | 176 std::ostream& operator<<(std::ostream& os, const V4Store& store) { |
| 177 os << store.DebugString(); | 177 os << store.DebugString(); |
| 178 return os; | 178 return os; |
| 179 } | 179 } |
| 180 | 180 |
| 181 V4Store* V4StoreFactory::CreateV4Store( | 181 V4Store* V4StoreFactory::CreateV4Store( |
| 182 const scoped_refptr<base::SequencedTaskRunner>& task_runner, | 182 const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| 183 const base::FilePath& store_path) { | 183 const base::FilePath& store_path) { |
| 184 V4Store* new_store = new V4Store(task_runner, store_path); | 184 V4Store* new_store = new V4Store(task_runner, store_path, 0); |
| 185 new_store->Initialize(); | 185 new_store->Initialize(); |
| 186 return new_store; | 186 return new_store; |
| 187 } | 187 } |
| 188 | 188 |
| 189 void V4Store::Initialize() { | 189 void V4Store::Initialize() { |
| 190 // If a state already exists, don't re-initilize. | 190 // If a state already exists, don't re-initilize. |
| 191 DCHECK(state_.empty()); | 191 DCHECK(state_.empty()); |
| 192 | 192 |
| 193 StoreReadResult store_read_result = ReadFromDisk(); | 193 StoreReadResult store_read_result = ReadFromDisk(); |
| 194 RecordStoreReadResult(store_read_result); | 194 RecordStoreReadResult(store_read_result); |
| 195 } | 195 } |
| 196 | 196 |
| 197 V4Store::V4Store(const scoped_refptr<base::SequencedTaskRunner>& task_runner, | 197 V4Store::V4Store(const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| 198 const base::FilePath& store_path) | 198 const base::FilePath& store_path, |
| 199 : store_path_(store_path), task_runner_(task_runner) {} | 199 const int64_t old_file_size) |
| 200 : file_size_(old_file_size), |
| 201 store_path_(store_path), |
| 202 task_runner_(task_runner) {} |
| 200 | 203 |
| 201 V4Store::~V4Store() { | 204 V4Store::~V4Store() { |
| 202 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 205 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 203 } | 206 } |
| 204 | 207 |
| 205 std::string V4Store::DebugString() const { | 208 std::string V4Store::DebugString() const { |
| 206 std::string state_base64; | 209 std::string state_base64; |
| 207 base::Base64Encode(state_, &state_base64); | 210 base::Base64Encode(state_, &state_base64); |
| 208 | 211 |
| 209 return base::StringPrintf("path: %" PRIsFP "; state: %s", | 212 return base::StringPrintf("path: %" PRIsFP "; state: %s", |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 RecordMergeUpdateTime(metric, TimeTicks::Now() - before, store_path_); | 343 RecordMergeUpdateTime(metric, TimeTicks::Now() - before, store_path_); |
| 341 | 344 |
| 342 state_ = response->new_client_state(); | 345 state_ = response->new_client_state(); |
| 343 return APPLY_UPDATE_SUCCESS; | 346 return APPLY_UPDATE_SUCCESS; |
| 344 } | 347 } |
| 345 | 348 |
| 346 void V4Store::ApplyUpdate( | 349 void V4Store::ApplyUpdate( |
| 347 std::unique_ptr<ListUpdateResponse> response, | 350 std::unique_ptr<ListUpdateResponse> response, |
| 348 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, | 351 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, |
| 349 UpdatedStoreReadyCallback callback) { | 352 UpdatedStoreReadyCallback callback) { |
| 350 std::unique_ptr<V4Store> new_store(new V4Store(task_runner_, store_path_)); | 353 std::unique_ptr<V4Store> new_store( |
| 354 new V4Store(task_runner_, store_path_, file_size_)); |
| 351 ApplyUpdateResult apply_update_result; | 355 ApplyUpdateResult apply_update_result; |
| 352 std::string metric; | 356 std::string metric; |
| 353 TimeTicks before = TimeTicks::Now(); | 357 TimeTicks before = TimeTicks::Now(); |
| 354 if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) { | 358 if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) { |
| 355 metric = kProcessPartialUpdate; | 359 metric = kProcessPartialUpdate; |
| 356 apply_update_result = new_store->ProcessPartialUpdateAndWriteToDisk( | 360 apply_update_result = new_store->ProcessPartialUpdateAndWriteToDisk( |
| 357 metric, hash_prefix_map_, std::move(response)); | 361 metric, hash_prefix_map_, std::move(response)); |
| 358 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) { | 362 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) { |
| 359 metric = kProcessFullUpdate; | 363 metric = kProcessFullUpdate; |
| 360 apply_update_result = | 364 apply_update_result = |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 } | 654 } |
| 651 } | 655 } |
| 652 | 656 |
| 653 return APPLY_UPDATE_SUCCESS; | 657 return APPLY_UPDATE_SUCCESS; |
| 654 } | 658 } |
| 655 | 659 |
| 656 StoreReadResult V4Store::ReadFromDisk() { | 660 StoreReadResult V4Store::ReadFromDisk() { |
| 657 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 661 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 658 | 662 |
| 659 V4StoreFileFormat file_format; | 663 V4StoreFileFormat file_format; |
| 664 int64_t file_size; |
| 660 TimeTicks before = TimeTicks::Now(); | 665 TimeTicks before = TimeTicks::Now(); |
| 661 { | 666 { |
| 662 // A temporary scope to make sure that |contents| get destroyed as soon as | 667 // A temporary scope to make sure that |contents| get destroyed as soon as |
| 663 // we are doing using it. | 668 // we are doing using it. |
| 664 std::string contents; | 669 std::string contents; |
| 665 bool read_success = base::ReadFileToString(store_path_, &contents); | 670 bool read_success = base::ReadFileToString(store_path_, &contents); |
| 666 if (!read_success) { | 671 if (!read_success) { |
| 667 return FILE_UNREADABLE_FAILURE; | 672 return FILE_UNREADABLE_FAILURE; |
| 668 } | 673 } |
| 669 | 674 |
| 670 if (contents.empty()) { | 675 if (contents.empty()) { |
| 671 return FILE_EMPTY_FAILURE; | 676 return FILE_EMPTY_FAILURE; |
| 672 } | 677 } |
| 673 | 678 |
| 674 if (!file_format.ParseFromString(contents)) { | 679 if (!file_format.ParseFromString(contents)) { |
| 675 return PROTO_PARSING_FAILURE; | 680 return PROTO_PARSING_FAILURE; |
| 676 } | 681 } |
| 682 file_size = static_cast<int64_t>(contents.size()); |
| 677 } | 683 } |
| 678 | 684 |
| 679 if (file_format.magic_number() != kFileMagic) { | 685 if (file_format.magic_number() != kFileMagic) { |
| 680 return UNEXPECTED_MAGIC_NUMBER_FAILURE; | 686 return UNEXPECTED_MAGIC_NUMBER_FAILURE; |
| 681 } | 687 } |
| 682 | 688 |
| 683 UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.V4StoreVersionRead", | 689 UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.V4StoreVersionRead", |
| 684 file_format.version_number()); | 690 file_format.version_number()); |
| 685 if (file_format.version_number() != kFileVersion) { | 691 if (file_format.version_number() != kFileVersion) { |
| 686 return FILE_VERSION_INCOMPATIBLE_FAILURE; | 692 return FILE_VERSION_INCOMPATIBLE_FAILURE; |
| 687 } | 693 } |
| 688 | 694 |
| 689 if (!file_format.has_list_update_response()) { | 695 if (!file_format.has_list_update_response()) { |
| 690 return HASH_PREFIX_INFO_MISSING_FAILURE; | 696 return HASH_PREFIX_INFO_MISSING_FAILURE; |
| 691 } | 697 } |
| 692 | 698 |
| 693 std::unique_ptr<ListUpdateResponse> response(new ListUpdateResponse); | 699 std::unique_ptr<ListUpdateResponse> response(new ListUpdateResponse); |
| 694 response->Swap(file_format.mutable_list_update_response()); | 700 response->Swap(file_format.mutable_list_update_response()); |
| 695 ApplyUpdateResult apply_update_result = ProcessFullUpdate( | 701 ApplyUpdateResult apply_update_result = ProcessFullUpdate( |
| 696 kReadFromDisk, response, true /* delay_checksum check */); | 702 kReadFromDisk, response, true /* delay_checksum check */); |
| 697 RecordApplyUpdateResult(kReadFromDisk, apply_update_result, store_path_); | 703 RecordApplyUpdateResult(kReadFromDisk, apply_update_result, store_path_); |
| 698 if (apply_update_result != APPLY_UPDATE_SUCCESS) { | 704 if (apply_update_result != APPLY_UPDATE_SUCCESS) { |
| 699 hash_prefix_map_.clear(); | 705 hash_prefix_map_.clear(); |
| 700 return HASH_PREFIX_MAP_GENERATION_FAILURE; | 706 return HASH_PREFIX_MAP_GENERATION_FAILURE; |
| 701 } | 707 } |
| 702 RecordApplyUpdateTime(kReadFromDisk, TimeTicks::Now() - before, store_path_); | 708 RecordApplyUpdateTime(kReadFromDisk, TimeTicks::Now() - before, store_path_); |
| 703 | 709 |
| 710 // Update |file_size_| now because we parsed the file correctly. |
| 711 file_size_ = file_size; |
| 712 |
| 704 return READ_SUCCESS; | 713 return READ_SUCCESS; |
| 705 } | 714 } |
| 706 | 715 |
| 707 StoreWriteResult V4Store::WriteToDisk(const Checksum& checksum) const { | 716 StoreWriteResult V4Store::WriteToDisk(const Checksum& checksum) { |
| 708 V4StoreFileFormat file_format; | 717 V4StoreFileFormat file_format; |
| 709 ListUpdateResponse* lur = file_format.mutable_list_update_response(); | 718 ListUpdateResponse* lur = file_format.mutable_list_update_response(); |
| 710 *(lur->mutable_checksum()) = checksum; | 719 *(lur->mutable_checksum()) = checksum; |
| 711 lur->set_new_client_state(state_); | 720 lur->set_new_client_state(state_); |
| 712 lur->set_response_type(ListUpdateResponse::FULL_UPDATE); | 721 lur->set_response_type(ListUpdateResponse::FULL_UPDATE); |
| 713 for (auto map_iter : hash_prefix_map_) { | 722 for (auto map_iter : hash_prefix_map_) { |
| 714 ThreatEntrySet* additions = lur->add_additions(); | 723 ThreatEntrySet* additions = lur->add_additions(); |
| 715 // TODO(vakh): Write RICE encoded hash prefixes on disk. Not doing so | 724 // TODO(vakh): Write RICE encoded hash prefixes on disk. Not doing so |
| 716 // currently since it takes a long time to decode them on startup, which | 725 // currently since it takes a long time to decode them on startup, which |
| 717 // blocks resource load. See: http://crbug.com/654819 | 726 // blocks resource load. See: http://crbug.com/654819 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 728 std::string file_format_string; | 737 std::string file_format_string; |
| 729 file_format.SerializeToString(&file_format_string); | 738 file_format.SerializeToString(&file_format_string); |
| 730 size_t written = base::WriteFile(new_filename, file_format_string.data(), | 739 size_t written = base::WriteFile(new_filename, file_format_string.data(), |
| 731 file_format_string.size()); | 740 file_format_string.size()); |
| 732 DCHECK_EQ(file_format_string.size(), written); | 741 DCHECK_EQ(file_format_string.size(), written); |
| 733 | 742 |
| 734 if (!base::Move(new_filename, store_path_)) { | 743 if (!base::Move(new_filename, store_path_)) { |
| 735 return UNABLE_TO_RENAME_FAILURE; | 744 return UNABLE_TO_RENAME_FAILURE; |
| 736 } | 745 } |
| 737 | 746 |
| 747 // Update |file_size_| now because we wrote the file correctly. |
| 748 file_size_ = static_cast<int64_t>(written); |
| 749 |
| 738 return WRITE_SUCCESS; | 750 return WRITE_SUCCESS; |
| 739 } | 751 } |
| 740 | 752 |
| 741 HashPrefix V4Store::GetMatchingHashPrefix(const FullHash& full_hash) { | 753 HashPrefix V4Store::GetMatchingHashPrefix(const FullHash& full_hash) { |
| 742 // It should never be the case that more than one hash prefixes match a given | 754 // It should never be the case that more than one hash prefixes match a given |
| 743 // full hash. However, if that happens, this method returns any one of them. | 755 // full hash. However, if that happens, this method returns any one of them. |
| 744 // It does not guarantee which one of those will be returned. | 756 // It does not guarantee which one of those will be returned. |
| 745 DCHECK_EQ(32u, full_hash.size()); | 757 DCHECK_EQ(32u, full_hash.size()); |
| 746 for (const auto& pair : hash_prefix_map_) { | 758 for (const auto& pair : hash_prefix_map_) { |
| 747 const PrefixSize& prefix_size = pair.first; | 759 const PrefixSize& prefix_size = pair.first; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_b64 | 837 DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_b64 |
| 826 << "; expected: " << expected_checksum_b64 | 838 << "; expected: " << expected_checksum_b64 |
| 827 << "; store: " << *this; | 839 << "; store: " << *this; |
| 828 #endif | 840 #endif |
| 829 return false; | 841 return false; |
| 830 } | 842 } |
| 831 } | 843 } |
| 832 return true; | 844 return true; |
| 833 } | 845 } |
| 834 | 846 |
| 847 int64_t V4Store::RecordAndReturnFileSize(const std::string& base_metric) { |
| 848 std::string suffix = GetUmaSuffixForStore(store_path_); |
| 849 // Histogram properties as in UMA_HISTOGRAM_COUNTS macro. |
| 850 base::HistogramBase* histogram = base::Histogram::FactoryGet( |
| 851 base_metric + suffix, 1, 1000000, 50, |
| 852 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 853 if (histogram) { |
| 854 const int64_t file_size_kilobytes = file_size_ / 1024; |
| 855 histogram->Add(file_size_kilobytes); |
| 856 } |
| 857 return file_size_; |
| 858 } |
| 859 |
| 835 } // namespace safe_browsing | 860 } // namespace safe_browsing |
| OLD | NEW |