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

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

Issue 2233103002: Move full hash caching logic to v4_get_hash_protocol_manager (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "components/safe_browsing_db/database_manager.h" 5 #include "components/safe_browsing_db/database_manager.h"
6 6
7 #include "base/metrics/histogram_macros.h" 7 #include "base/metrics/histogram_macros.h"
8 #include "components/safe_browsing_db/v4_get_hash_protocol_manager.h" 8 #include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
9 #include "content/public/browser/browser_thread.h" 9 #include "content/public/browser/browser_thread.h"
10 #include "net/url_request/url_request_context_getter.h" 10 #include "net/url_request/url_request_context_getter.h"
11 #include "url/gurl.h" 11 #include "url/gurl.h"
12 12
13 using content::BrowserThread; 13 using content::BrowserThread;
14 14
15 namespace { 15 namespace {
16 16
17 // Enumerate full hash cache hits/misses for histogramming purposes.
18 // DO NOT CHANGE THE ORDERING OF THESE VALUES.
19 enum V4FullHashCacheResultType {
20 // Full hashes for which there is no cache hit.
21 FULL_HASH_CACHE_MISS = 0,
22
23 // Full hashes with a cache hit.
24 FULL_HASH_CACHE_HIT = 1,
25
26 // Full hashes with a negative cache hit.
27 FULL_HASH_NEGATIVE_CACHE_HIT = 2,
28
29 // Memory space for histograms is determined by the max. ALWAYS
30 // ADD NEW VALUES BEFORE THIS ONE.
31 FULL_HASH_CACHE_RESULT_MAX
32 };
33
34 // Enumerate GetHash hits/misses for histogramming purposes. DO NOT CHANGE THE 17 // Enumerate GetHash hits/misses for histogramming purposes. DO NOT CHANGE THE
35 // ORDERING OF THESE VALUES. 18 // ORDERING OF THESE VALUES.
36 enum V4GetHashCheckResultType { 19 enum V4GetHashCheckResultType {
37 // Successful responses which returned no full hashes. 20 // Successful responses which returned no full hashes.
38 GET_HASH_CHECK_EMPTY = 0, 21 GET_HASH_CHECK_EMPTY = 0,
39 22
40 // Successful responses for which one or more of the full hashes matched. 23 // Successful responses for which one or more of the full hashes matched.
41 GET_HASH_CHECK_HIT = 1, 24 GET_HASH_CHECK_HIT = 1,
42 25
43 // Successful responses which weren't empty but have no matches. 26 // Successful responses which weren't empty but have no matches.
44 GET_HASH_CHECK_MISS = 2, 27 GET_HASH_CHECK_MISS = 2,
45 28
46 // Memory space for histograms is determined by the max. ALWAYS 29 // Memory space for histograms is determined by the max. ALWAYS
47 // ADD NEW VALUES BEFORE THIS ONE. 30 // ADD NEW VALUES BEFORE THIS ONE.
48 GET_HASH_CHECK_RESULT_MAX 31 GET_HASH_CHECK_RESULT_MAX
49 }; 32 };
50 33
51 // Record a full hash cache hit result.
52 void RecordV4FullHashCacheResult(
53 V4FullHashCacheResultType result_type) {
54 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4FullHashCacheResult", result_type,
55 FULL_HASH_CACHE_RESULT_MAX);
56 }
57
58 // Record a GetHash hit result. 34 // Record a GetHash hit result.
59 void RecordV4GetHashCheckResult( 35 void RecordV4GetHashCheckResult(
60 V4GetHashCheckResultType result_type) { 36 V4GetHashCheckResultType result_type) {
61 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4GetHashCheckResult", result_type, 37 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4GetHashCheckResult", result_type,
62 GET_HASH_CHECK_RESULT_MAX); 38 GET_HASH_CHECK_RESULT_MAX);
63 } 39 }
64 40
65 } // namespace 41 } // namespace
66 42
67 namespace safe_browsing { 43 namespace safe_browsing {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 if (full_hashes.empty()) 123 if (full_hashes.empty())
148 return true; 124 return true;
149 125
150 // First check the cache. 126 // First check the cache.
151 127
152 // Used to determine cache expiration. 128 // Used to determine cache expiration.
153 base::Time now = base::Time::Now(); 129 base::Time now = base::Time::Now();
154 130
155 std::vector<SBFullHashResult> cached_results; 131 std::vector<SBFullHashResult> cached_results;
156 std::vector<SBPrefix> prefixes_needing_reqs; 132 std::vector<SBPrefix> prefixes_needing_reqs;
157 GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, 133 v4_get_hash_protocol_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABU SE,
Nathan Parker 2016/08/15 19:54:47 How about moving all of this code into v4_get_hash
158 full_hashes, now, &prefixes_needing_reqs, &cached_results); 134 full_hashes, now, &prefixes_needing_reqs, &cached_results);
159 135
160 if (prefixes_needing_reqs.empty() && cached_results.empty()) 136 if (prefixes_needing_reqs.empty() && cached_results.empty())
161 return true; 137 return true;
162 138
163 SafeBrowsingApiCheck* check = 139 SafeBrowsingApiCheck* check =
164 new SafeBrowsingApiCheck(url, prefixes_needing_reqs, full_hashes, 140 new SafeBrowsingApiCheck(url, prefixes_needing_reqs, full_hashes,
165 cached_results, client); 141 cached_results, client);
166 api_checks_.insert(check); 142 api_checks_.insert(check);
167 143
168 if (prefixes_needing_reqs.empty()) { 144 if (prefixes_needing_reqs.empty()) {
169 check->set_start_time(base::TimeTicks::Now()); 145 check->set_start_time(base::TimeTicks::Now());
170 // We can call the callback immediately if no prefixes require a request. 146 // We can call the callback immediately if no prefixes require a request.
171 // The |full_hash_results| representing the results fromt eh SB server will 147 // The |full_hash_results| representing the results fromt eh SB server will
172 // be empty. 148 // be empty.
173 std::vector<SBFullHashResult> full_hash_results; 149 std::vector<SBFullHashResult> full_hash_results;
174 HandleGetHashesWithApisResults(check, full_hash_results, base::Time()); 150 HandleGetHashesWithApisResults(check, full_hash_results, base::Time());
175 return false; 151 return false;
176 } 152 }
177 153
178 v4_get_hash_protocol_manager_->GetFullHashesWithApis(prefixes_needing_reqs, 154 v4_get_hash_protocol_manager_->GetFullHashesWithApis(prefixes_needing_reqs,
179 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashesWithApisResults, 155 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashesWithApisResults,
180 base::Unretained(this), check)); 156 base::Unretained(this), check));
181 157
182 return false; 158 return false;
183 } 159 }
184 160
185 void SafeBrowsingDatabaseManager::GetFullHashCachedResults(
186 const SBThreatType& threat_type,
187 const std::vector<SBFullHash>& full_hashes,
188 base::Time now,
189 std::vector<SBPrefix>* prefixes_needing_reqs,
190 std::vector<SBFullHashResult>* cached_results) {
191 DCHECK(prefixes_needing_reqs);
192 prefixes_needing_reqs->clear();
193 DCHECK(cached_results);
194 cached_results->clear();
195
196 // Caching behavior is documented here:
197 // https://developers.google.com/safe-browsing/v4/caching#about-caching
198 //
199 // The cache operates as follows:
200 // Lookup:
201 // Case 1: The prefix is in the cache.
202 // Case a: The full hash is in the cache.
203 // Case i : The positive full hash result has not expired.
204 // The result is unsafe and we do not need to send a new
205 // request.
206 // Case ii: The positive full hash result has expired.
207 // We need to send a request for full hashes.
208 // Case b: The full hash is not in the cache.
209 // Case i : The negative cache entry has not expired.
210 // The result is still safe and we do not need to send a
211 // new request.
212 // Case ii: The negative cache entry has expired.
213 // We need to send a request for full hashes.
214 // Case 2: The prefix is not in the cache.
215 // We need to send a request for full hashes.
216 //
217 // Eviction:
218 // SBCachedFullHashResult entries can be removed from the cache only when
219 // the negative cache expire time and the cache expire time of all full
220 // hash results for that prefix have expired.
221 // Individual full hash results can be removed from the prefix's
222 // cache entry if they expire AND their expire time is after the negative
223 // cache expire time.
224 for (const SBFullHash& full_hash : full_hashes) {
225 auto entry = v4_full_hash_cache_[threat_type].find(full_hash.prefix);
226 if (entry != v4_full_hash_cache_[threat_type].end()) {
227 // Case 1.
228 SBCachedFullHashResult& cache_result = entry->second;
229
230 const SBFullHashResult* found_full_hash = nullptr;
231 size_t matched_idx = 0;
232 for (const SBFullHashResult& hash_result : cache_result.full_hashes) {
233 if (SBFullHashEqual(full_hash, hash_result.hash)) {
234 found_full_hash = &hash_result;
235 break;
236 }
237 ++matched_idx;
238 }
239
240 if (found_full_hash) {
241 // Case a.
242 if (found_full_hash->cache_expire_after > now) {
243 // Case i.
244 cached_results->push_back(*found_full_hash);
245 RecordV4FullHashCacheResult(FULL_HASH_CACHE_HIT);
246 } else {
247 // Case ii.
248 prefixes_needing_reqs->push_back(full_hash.prefix);
249 RecordV4FullHashCacheResult(FULL_HASH_CACHE_MISS);
250 // If the negative cache expire time has passed, evict this full hash
251 // result from the cache.
252 if (cache_result.expire_after <= now) {
253 cache_result.full_hashes.erase(
254 cache_result.full_hashes.begin() + matched_idx);
255 // If there are no more full hashes, we can evict the entire entry.
256 if (cache_result.full_hashes.empty()) {
257 v4_full_hash_cache_[threat_type].erase(entry);
258 }
259 }
260 }
261 } else {
262 // Case b.
263 if (cache_result.expire_after > now) {
264 // Case i.
265 RecordV4FullHashCacheResult(FULL_HASH_NEGATIVE_CACHE_HIT);
266 } else {
267 // Case ii.
268 prefixes_needing_reqs->push_back(full_hash.prefix);
269 RecordV4FullHashCacheResult(FULL_HASH_CACHE_MISS);
270 }
271 }
272 } else {
273 // Case 2.
274 prefixes_needing_reqs->push_back(full_hash.prefix);
275 RecordV4FullHashCacheResult(FULL_HASH_CACHE_MISS);
276 }
277 }
278
279 // Multiple full hashes could share a prefix, remove duplicates.
280 // TODO(kcarattini): Make |prefixes_needing_reqs| a set.
281 std::sort(prefixes_needing_reqs->begin(), prefixes_needing_reqs->end());
282 prefixes_needing_reqs->erase(std::unique(prefixes_needing_reqs->begin(),
283 prefixes_needing_reqs->end()), prefixes_needing_reqs->end());
284 }
285
286 void SafeBrowsingDatabaseManager::HandleGetHashesWithApisResults( 161 void SafeBrowsingDatabaseManager::HandleGetHashesWithApisResults(
287 SafeBrowsingApiCheck* check, 162 SafeBrowsingApiCheck* check,
288 const std::vector<SBFullHashResult>& full_hash_results, 163 const std::vector<SBFullHashResult>& full_hash_results,
289 const base::Time& negative_cache_expire) { 164 const base::Time& negative_cache_expire) {
290 DCHECK_CURRENTLY_ON(BrowserThread::IO); 165 DCHECK_CURRENTLY_ON(BrowserThread::IO);
291 DCHECK(check); 166 DCHECK(check);
292 167
293 // Record the network time. 168 // Record the network time.
294 if (!check->start_time().is_null()) { 169 if (!check->start_time().is_null()) {
295 UMA_HISTOGRAM_LONG_TIMES("SafeBrowsing.GetV4HashNetwork", 170 UMA_HISTOGRAM_LONG_TIMES("SafeBrowsing.GetV4HashNetwork",
296 base::TimeTicks::Now() - check->start_time()); 171 base::TimeTicks::Now() - check->start_time());
297 } 172 }
298 173
299 // If the time is uninitialized, don't cache the results.
300 if (!negative_cache_expire.is_null()) {
301 // Cache the results.
302 // Create or reset all cached results for this prefix.
303 for (const SBPrefix& prefix : check->prefixes()) {
304 v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE][prefix] =
305 SBCachedFullHashResult(negative_cache_expire);
306 }
307 // Insert any full hash hits. Note that there may be one, multiple, or no
308 // full hashes for any given prefix.
309 for (const SBFullHashResult& result : full_hash_results) {
310 v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE][result.hash.prefix].
311 full_hashes.push_back(result);
312 }
313 }
314
315 // If the check is not in |api_checks_| then the request was cancelled by the 174 // If the check is not in |api_checks_| then the request was cancelled by the
316 // client. 175 // client.
317 ApiCheckSet::iterator it = api_checks_.find(check); 176 ApiCheckSet::iterator it = api_checks_.find(check);
318 if (it == api_checks_.end()) 177 if (it == api_checks_.end())
319 return; 178 return;
320 179
321 ThreatMetadata md; 180 ThreatMetadata md;
322 // Merge the metadata from all matching results. 181 // Merge the metadata from all matching results.
323 // Note: A full hash may have a result in both the cached results (from 182 // Note: A full hash may have a result in both the cached results (from
324 // its own cache lookup) and in the server results (if another full hash 183 // its own cache lookup) and in the server results (if another full hash
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 const std::vector<SBFullHashResult>& cached_results, 228 const std::vector<SBFullHashResult>& cached_results,
370 Client* client) 229 Client* client)
371 : url_(url), prefixes_(prefixes), full_hashes_(full_hashes), 230 : url_(url), prefixes_(prefixes), full_hashes_(full_hashes),
372 cached_results_(cached_results), client_(client) { 231 cached_results_(cached_results), client_(client) {
373 } 232 }
374 233
375 SafeBrowsingDatabaseManager::SafeBrowsingApiCheck::~SafeBrowsingApiCheck() { 234 SafeBrowsingDatabaseManager::SafeBrowsingApiCheck::~SafeBrowsingApiCheck() {
376 } 235 }
377 236
378 } // namespace safe_browsing 237 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698