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" | |
| 8 #include "base/metrics/histogram.h" | |
|
rkaplow
2016/06/27 17:48:51
histogram_macros.h
| |
| 9 #include "base/metrics/sparse_histogram.h" | |
| 7 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 8 #include "components/safe_browsing_db/v4_store.h" | 11 #include "components/safe_browsing_db/v4_store.h" |
| 12 #include "components/safe_browsing_db/v4_store.pb.h" | |
| 9 | 13 |
| 10 namespace safe_browsing { | 14 namespace safe_browsing { |
| 11 | 15 |
| 16 namespace { | |
| 17 const uint32_t kFileMagic = 0x600D71FE; | |
| 18 | |
| 19 const uint32_t kFileVersion = 9; | |
| 20 | |
| 21 void RecordStoreReadResult(StoreReadResult result) { | |
| 22 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreReadResult", result, | |
| 23 STORE_READ_RESULT_MAX); | |
| 24 } | |
| 25 | |
| 26 void RecordStoreWriteResult(StoreWriteResult result) { | |
| 27 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreWriteResult", result, | |
| 28 STORE_WRITE_RESULT_MAX); | |
| 29 } | |
| 30 | |
| 31 // Returns the name of the temporary file used to buffer data for | |
| 32 // |filename|. Exported for unit tests. | |
| 33 const base::FilePath TemporaryFileForFilename(const base::FilePath& filename) { | |
| 34 return base::FilePath(filename.value() + FILE_PATH_LITERAL("_new")); | |
| 35 } | |
| 36 | |
| 37 } // namespace | |
| 38 | |
| 12 std::ostream& operator<<(std::ostream& os, const V4Store& store) { | 39 std::ostream& operator<<(std::ostream& os, const V4Store& store) { |
| 13 os << store.DebugString(); | 40 os << store.DebugString(); |
| 14 return os; | 41 return os; |
| 15 } | 42 } |
| 16 | 43 |
| 17 V4Store* V4StoreFactory::CreateV4Store( | 44 V4Store* V4StoreFactory::CreateV4Store( |
| 18 const scoped_refptr<base::SequencedTaskRunner>& task_runner, | 45 const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| 19 const base::FilePath& store_path) { | 46 const base::FilePath& store_path) { |
| 20 return new V4Store(task_runner, store_path); | 47 V4Store* new_store = new V4Store(task_runner, store_path); |
| 48 new_store->Initialize(); | |
| 49 return new_store; | |
| 50 } | |
| 51 | |
| 52 void V4Store::Initialize() { | |
| 53 // If a state already exists, don't re-initilize. | |
| 54 DCHECK(state_.empty()); | |
| 55 | |
| 56 StoreReadResult store_read_result = ReadFromDisk(); | |
| 57 RecordStoreReadResult(store_read_result); | |
| 21 } | 58 } |
| 22 | 59 |
| 23 V4Store::V4Store(const scoped_refptr<base::SequencedTaskRunner>& task_runner, | 60 V4Store::V4Store(const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| 24 const base::FilePath& store_path) | 61 const base::FilePath& store_path) |
| 25 : store_path_(store_path), task_runner_(task_runner) {} | 62 : store_path_(store_path), task_runner_(task_runner) {} |
| 26 | 63 |
| 27 V4Store::~V4Store() {} | 64 V4Store::~V4Store() {} |
| 28 | 65 |
| 29 std::string V4Store::DebugString() const { | 66 std::string V4Store::DebugString() const { |
| 30 std::string state_base64; | 67 std::string state_base64; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 43 void V4Store::ApplyUpdate( | 80 void V4Store::ApplyUpdate( |
| 44 const ListUpdateResponse& response, | 81 const ListUpdateResponse& response, |
| 45 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, | 82 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, |
| 46 UpdatedStoreReadyCallback callback) { | 83 UpdatedStoreReadyCallback callback) { |
| 47 std::unique_ptr<V4Store> new_store( | 84 std::unique_ptr<V4Store> new_store( |
| 48 new V4Store(this->task_runner_, this->store_path_)); | 85 new V4Store(this->task_runner_, this->store_path_)); |
| 49 | 86 |
| 50 // TODO(vakh): The new store currently only picks up the new state. Do more. | 87 // TODO(vakh): The new store currently only picks up the new state. Do more. |
| 51 new_store->state_ = response.new_client_state(); | 88 new_store->state_ = response.new_client_state(); |
| 52 | 89 |
| 90 // TODO(vakh): Merge the old store and the new update in new_store. | |
| 91 // Then, create a ListUpdateResponse containing RICE encoded hash-prefixes and | |
| 92 // response_type as FULL_UPDATE, and write that to disk. | |
| 93 StoreWriteResult result = new_store->WriteToDisk(response); | |
| 94 RecordStoreWriteResult(result); | |
| 95 | |
| 53 // new_store is done updating, pass it to the callback. | 96 // new_store is done updating, pass it to the callback. |
| 54 callback_task_runner->PostTask( | 97 callback_task_runner->PostTask( |
| 55 FROM_HERE, base::Bind(callback, base::Passed(&new_store))); | 98 FROM_HERE, base::Bind(callback, base::Passed(&new_store))); |
| 56 } | 99 } |
| 57 | 100 |
| 101 StoreReadResult V4Store::ReadFromDisk() { | |
| 102 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
| 103 | |
| 104 std::string contents; | |
| 105 bool read_success = base::ReadFileToString(store_path_, &contents); | |
| 106 if (!read_success) { | |
| 107 return FILE_UNREADABLE_FAILURE; | |
| 108 } | |
| 109 | |
| 110 if (contents.empty()) { | |
| 111 return FILE_EMPTY_FAILURE; | |
| 112 } | |
| 113 | |
| 114 V4StoreFileFormat file_format; | |
| 115 if (!file_format.ParseFromString(contents)) { | |
| 116 return PROTO_PARSING_FAILURE; | |
| 117 } | |
| 118 | |
| 119 if (file_format.magic_number() != kFileMagic) { | |
| 120 DVLOG(1) << "Unexpected magic number found in file: " | |
| 121 << file_format.magic_number(); | |
| 122 return UNEXPECTED_MAGIC_NUMBER_FAILURE; | |
| 123 } | |
| 124 | |
| 125 UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.V4StoreVersionRead", | |
| 126 file_format.version_number()); | |
| 127 if (file_format.version_number() != kFileVersion) { | |
| 128 DVLOG(1) << "File version incompatible: " << file_format.version_number() | |
| 129 << "; expected: " << kFileVersion; | |
| 130 return FILE_VERSION_INCOMPATIBLE_FAILURE; | |
| 131 } | |
| 132 | |
| 133 if (!file_format.has_list_update_response()) { | |
| 134 return HASH_PREFIX_INFO_MISSING_FAILURE; | |
| 135 } | |
| 136 | |
| 137 ListUpdateResponse list_update_response = file_format.list_update_response(); | |
| 138 state_ = list_update_response.new_client_state(); | |
| 139 // TODO(vakh): Do more with what's read from the disk. | |
| 140 | |
| 141 return READ_SUCCESS; | |
| 142 } | |
| 143 | |
| 144 StoreWriteResult V4Store::WriteToDisk( | |
| 145 const ListUpdateResponse& response) const { | |
| 146 // Do not write partial updates to the disk. | |
| 147 // After merging the updates, the ListUpdateResponse passed to this method | |
| 148 // should be a FULL_UPDATE. | |
| 149 if (!response.has_response_type() || | |
| 150 response.response_type() != ListUpdateResponse::FULL_UPDATE) { | |
| 151 DVLOG(1) << "response.has_response_type(): " | |
| 152 << response.has_response_type(); | |
| 153 DVLOG(1) << "response.response_type(): " << response.response_type(); | |
| 154 return INVALID_RESPONSE_TYPE_FAILURE; | |
| 155 } | |
| 156 | |
| 157 // Attempt writing to a temporary file first and at the end, swap the files. | |
| 158 const base::FilePath new_filename = TemporaryFileForFilename(store_path_); | |
| 159 | |
| 160 V4StoreFileFormat file_format; | |
| 161 file_format.set_magic_number(kFileMagic); | |
| 162 file_format.set_version_number(kFileVersion); | |
| 163 ListUpdateResponse* response_to_write = | |
| 164 file_format.mutable_list_update_response(); | |
| 165 *response_to_write = response; | |
| 166 std::string file_format_string; | |
| 167 file_format.SerializeToString(&file_format_string); | |
| 168 size_t written = base::WriteFile(new_filename, file_format_string.data(), | |
| 169 file_format_string.size()); | |
| 170 DCHECK_EQ(file_format_string.size(), written); | |
| 171 | |
| 172 if (!base::Move(new_filename, store_path_)) { | |
| 173 DVLOG(1) << "store_path_: " << store_path_.value(); | |
| 174 return UNABLE_TO_RENAME_FAILURE; | |
| 175 } | |
| 176 | |
| 177 return WRITE_SUCCESS; | |
| 178 } | |
| 179 | |
| 58 } // namespace safe_browsing | 180 } // namespace safe_browsing |
| OLD | NEW |