Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: components/safe_browsing_db/v4_store.cc

Issue 2066083002: SafeBrowising: Read and write V4Store from/to disk (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@01_UpdateDbAndStores
Patch Set: Nit: better test names. Tests for WriteToDisk Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
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 // NOTE(vakh): kFileMagic should not be a byte-wise palindrome, so
18 // that byte-order changes force corruption.
19 const uint32_t kFileMagic = 0x600D71FE;
20
21 const uint32_t kFileVersion = 9;
22
23 void RecordStoreReadFailure(StoreReadFailureType event_type) {
24 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreReadEvent", event_type,
25 FORMAT_FAILURE_MAX);
26 }
27
28 } // namespace
29
12 V4Store* V4StoreFactory::CreateV4Store( 30 V4Store* V4StoreFactory::CreateV4Store(
13 const scoped_refptr<base::SequencedTaskRunner>& task_runner, 31 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
14 const base::FilePath& store_path) { 32 const base::FilePath& store_path) {
15 return new V4Store(task_runner, store_path); 33 V4Store* new_store = new V4Store(task_runner, store_path);
34 new_store->Initialize();
35 return new_store;
36 }
37
38 void V4Store::Initialize() {
39 // If a state already exists, don't re-initilize.
Nathan Parker 2016/06/16 00:07:50 Would this indicate a bug? You could dcheck then.
vakh (use Gerrit instead) 2016/06/16 08:25:18 Done.
40 if (!state_.empty()) {
41 return;
42 }
43
44 StoreReadFailureType store_read_failure_type = ReadFromDisk();
Nathan Parker 2016/06/16 00:07:50 nit:How about StoreReadResult? FailureType doesn'
vakh (use Gerrit instead) 2016/06/16 08:25:18 Done.
45 RecordStoreReadFailure(store_read_failure_type);
46 DVLOG(1) << "Loaded V4Store: " << *this;
47 DVLOG(1) << "store_read_failure_type: " << store_read_failure_type;
16 } 48 }
17 49
18 V4Store::V4Store(const scoped_refptr<base::SequencedTaskRunner>& task_runner, 50 V4Store::V4Store(const scoped_refptr<base::SequencedTaskRunner>& task_runner,
19 const base::FilePath& store_path) 51 const base::FilePath& store_path)
20 : task_runner_(task_runner), store_path_(store_path) {} 52 : task_runner_(task_runner), store_path_(store_path) {}
21 53
22 V4Store::V4Store(const V4Store& other) 54 V4Store::V4Store(const V4Store& other)
23 : task_runner_(other.task_runner_), store_path_(other.store_path_) {} 55 : task_runner_(other.task_runner_), store_path_(other.store_path_) {}
24 56
25 V4Store::~V4Store() { 57 V4Store::~V4Store() {
(...skipping 15 matching lines...) Expand all
41 } 73 }
42 74
43 void V4Store::ApplyUpdate( 75 void V4Store::ApplyUpdate(
44 const ListUpdateResponse& response, 76 const ListUpdateResponse& response,
45 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, 77 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
46 UpdatedStoreReadyCallback callback) { 78 UpdatedStoreReadyCallback callback) {
47 std::unique_ptr<V4Store> new_store(new V4Store(*this)); 79 std::unique_ptr<V4Store> new_store(new V4Store(*this));
48 80
49 // TODO(vakh): The new store currently only picks up the new state. Do more. 81 // TODO(vakh): The new store currently only picks up the new state. Do more.
50 new_store->state_ = response.new_client_state(); 82 new_store->state_ = response.new_client_state();
83 DVLOG(1) << "Created V4Store: " << *new_store;
51 84
52 DVLOG(1) << "Created V4Store: " << new_store->DebugString(); 85 // TODO(vakh): Merge the old store and the new update in new_store.
86 // Then, create a ListUpdateResponse containing RICE encoded hash-prefixes and
87 // response_type as FULL_UPDATE, and write that to disk.
88 new_store->WriteToDisk(response);
53 89
54 // new_store is done updataing, pass it to the callback. 90 // new_store is done updataing, pass it to the callback.
55 callback_task_runner->PostTask( 91 callback_task_runner->PostTask(
56 FROM_HERE, base::Bind(callback, base::Passed(&new_store))); 92 FROM_HERE, base::Bind(callback, base::Passed(&new_store)));
57 } 93 }
58 94
59 std::string V4Store::GetHumanReadableState() const { 95 std::string V4Store::GetHumanReadableState() const {
60 std::string state_base64; 96 std::string state_base64;
61 base::Base64Encode(state_, &state_base64); 97 base::Base64Encode(state_, &state_base64);
62 return state_base64; 98 return state_base64;
63 } 99 }
64 100
101 StoreReadFailureType V4Store::ReadFromDisk() {
102 DCHECK(task_runner_->RunsTasksOnCurrentThread());
103
104 std::string contents;
105 bool read_success = base::ReadFileToString(store_path_, &contents);
106 V4StoreFileFormat file_format;
107 if (!read_success) {
108 return FILE_UNREADABLE_FAILURE;
Nathan Parker 2016/06/16 00:07:50 It would be good to differentiate "non existent" f
vakh (use Gerrit instead) 2016/06/16 08:25:18 Acknowledged.
109 }
110
111 if (contents.empty()) {
112 return FILE_EMPTY_FAILURE;
113 }
114
115 if (!file_format.ParseFromString(contents)) {
116 return PROTO_PARSING_FAILURE;
117 }
118
119 if (!file_format.has_magic_number() ||
120 file_format.magic_number() != kFileMagic) {
121 DVLOG(1) << "Unexpected magic number found in file: "
122 << file_format.magic_number();
123 return UNEXPECTED_MAGIC_NUMBER_FAILURE;
124 }
125
126 UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.V4StoreVersionRead",
127 file_format.version_number());
128 if (!file_format.has_version_number() ||
129 file_format.version_number() < kFileVersion) {
Nathan Parker 2016/06/16 00:07:50 What does this protect against? It might be bette
vakh (use Gerrit instead) 2016/06/16 08:25:18 It provides the guarantee that we know we can pars
130 DVLOG(1) << "File version too low: " << file_format.version_number()
131 << "; expected: " << kFileVersion;
132 return FILE_VERSION_TOO_LOW_FAILURE;
Nathan Parker 2016/06/16 00:07:50 Then this would be FILE_VERSION_INCOMPATIBLE
vakh (use Gerrit instead) 2016/06/16 08:25:18 Done.
133 }
134
135 if (!file_format.has_list_update_response()) {
136 return HASH_PREFIX_INFO_MISSING_FAILURE;
137 }
138
139 ListUpdateResponse list_update_response = file_format.list_update_response();
140 state_ = list_update_response.new_client_state();
141 // TODO(vakh): Do more with what's read from the disk.
142
143 return SUCCESS;
144 }
145
146 bool V4Store::WriteToDisk(const ListUpdateResponse& response) const {
147 // Do not write partial updates to the disk.
148 // After merging the updates, the ListUpdateResponse passed to this method
149 // should be a FULL_UPDATE.
150 if (!response.has_response_type() ||
151 response.response_type() != ListUpdateResponse::FULL_UPDATE) {
152 return false;
153 }
154
155 V4StoreFileFormat file_format;
156 file_format.set_magic_number(kFileMagic);
157 file_format.set_version_number(kFileVersion);
158 ListUpdateResponse* response_to_write =
159 file_format.mutable_list_update_response();
160 *response_to_write = response;
Nathan Parker 2016/06/16 00:07:50 This is going to make a copy (big). Instead, you
vakh (use Gerrit instead) 2016/06/24 01:04:49 Acknowledged. I am going to try that as a separate
Scott Hess - ex-Googler 2016/06/24 19:51:17 I'd say to look at this comprehensively, starting
vakh (use Gerrit instead) 2016/06/27 19:54:21 I'm working on this. CL coming today (or tomorrow,
vakh (use Gerrit instead) 2016/06/28 01:34:43 https://codereview.chromium.org/2103693002/
vakh (use Gerrit instead) 2016/06/28 01:34:43 Here's the CL: https://codereview.chromium.org/210
161 std::string file_format_string;
162 file_format.SerializeToString(&file_format_string);
163
164 size_t written = base::WriteFile(store_path_, file_format_string.c_str(),
Nathan Parker 2016/06/16 00:07:50 We should write to a tmp file in the same dir (may
vakh (use Gerrit instead) 2016/06/22 07:26:06 Done.
165 file_format_string.size());
166 return file_format_string.size() == written;
Nathan Parker 2016/06/16 00:07:50 TODO: Add UMA metrics: * File size * Time it t
167 }
168
65 } // namespace safe_browsing 169 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698