OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |