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

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

Issue 2009183002: SafeBrowsing: Implement cache lookup for full hash checks (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Typo 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 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 "components/safe_browsing_db/v4_get_hash_protocol_manager.h" 7 #include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
8 #include "content/public/browser/browser_thread.h" 8 #include "content/public/browser/browser_thread.h"
9 #include "net/url_request/url_request_context_getter.h" 9 #include "net/url_request/url_request_context_getter.h"
10 #include "url/gurl.h" 10 #include "url/gurl.h"
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 87
88 // There can only be one in-progress check for the same client at a time. 88 // There can only be one in-progress check for the same client at a time.
89 DCHECK(FindClientApiCheck(client) == api_checks_.end()); 89 DCHECK(FindClientApiCheck(client) == api_checks_.end());
90 90
91 // Compute a list of hashes for this url. 91 // Compute a list of hashes for this url.
92 std::vector<SBFullHash> full_hashes; 92 std::vector<SBFullHash> full_hashes;
93 UrlToFullHashes(url, false, &full_hashes); 93 UrlToFullHashes(url, false, &full_hashes);
94 if (full_hashes.empty()) 94 if (full_hashes.empty())
95 return true; 95 return true;
96 96
97 // Copy to prefixes. 97 // First check the cache.
98 std::vector<SBPrefix> prefixes; 98
99 for (const SBFullHash& full_hash : full_hashes) { 99 // Used to determine cache expiration.
100 prefixes.push_back(full_hash.prefix); 100 base::Time now = base::Time::Now();
101 } 101
102 // Multiple full hashes could share a prefix, remove duplicates. 102 std::vector<SBFullHashResult> cached_results;
103 std::sort(prefixes.begin(), prefixes.end()); 103 std::vector<SBPrefix> prefixes_needing_reqs;
104 prefixes.erase(std::unique(prefixes.begin(), prefixes.end()), prefixes.end()); 104 GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE,
105 DCHECK(!prefixes.empty()); 105 full_hashes, now, &prefixes_needing_reqs, &cached_results);
106
107 if (prefixes_needing_reqs.empty() && cached_results.empty())
108 return true;
106 109
107 SafeBrowsingApiCheck* check = 110 SafeBrowsingApiCheck* check =
108 new SafeBrowsingApiCheck(url, prefixes, full_hashes, client); 111 new SafeBrowsingApiCheck(url, prefixes_needing_reqs, full_hashes,
112 cached_results, client);
109 api_checks_.insert(check); 113 api_checks_.insert(check);
110 114
111 // TODO(kcarattini): Implement cache compliance. 115 if (prefixes_needing_reqs.empty()) {
112 v4_get_hash_protocol_manager_->GetFullHashesWithApis(prefixes, 116 // We can call the callback immediately if no prefixes require a request.
117 // The |full_hash_results| representing the results fromt eh SB server will
118 // be empty.
119 std::vector<SBFullHashResult> full_hash_results;
120 HandleGetHashesWithApisResults(check, full_hash_results, base::Time());
121 return false;
122 }
123
124 v4_get_hash_protocol_manager_->GetFullHashesWithApis(prefixes_needing_reqs,
113 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashesWithApisResults, 125 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashesWithApisResults,
114 base::Unretained(this), check)); 126 base::Unretained(this), check));
115 127
116 return false; 128 return false;
117 } 129 }
118 130
131 void SafeBrowsingDatabaseManager::GetFullHashCachedResults(
132 const SBThreatType& threat_type,
133 const std::vector<SBFullHash>& full_hashes,
134 base::Time now,
135 std::vector<SBPrefix>* prefixes_needing_reqs,
136 std::vector<SBFullHashResult>* cached_results) {
137 DCHECK(prefixes_needing_reqs);
138 prefixes_needing_reqs->clear();
139 DCHECK(cached_results);
140 cached_results->clear();
141
142 // Caching behavior is documented here:
143 // https://developers.google.com/safe-browsing/v4/caching#about-caching
144 //
145 // The cache operates as follows:
146 // Lookup:
147 // Case 1: The prefix is in the cache.
148 // Case a: The full hash is in the cache.
149 // Case i : The positive full hash result has not expired.
150 // The result is unsafe and we do not need to send a new
151 // request.
152 // Case ii: The positive full hash result has expired.
153 // We need to send a request for full hashes.
154 // Case b: The full hash is not in the cache.
155 // Case i : The negative cache entry has not expired.
156 // The result is still safe and we do not need to send a
157 // new request.
158 // Case ii: The negative cache entry has expired.
159 // We need to send a request for full hashes.
160 // Case 2: The prefix is not in the cache.
161 // We need to send a request for full hashes.
162 //
163 // Eviction:
164 // SBCachedFullHashResult entries can be removed from the cache only when
165 // the negative cache expire time and the cache expire time of all full
166 // hash results for that prefix have expired.
167 // Individual full hash results can be removed from the prefix's
168 // cache entry if they expire AND their expire time is after the negative
169 // cache expire time.
170 //
171 // TODO(kcarattini): Implement cache eviction.
172 for (const SBFullHash& full_hash : full_hashes) {
173 auto entry = v4_full_hash_cache_[threat_type].find(full_hash.prefix);
174 if (entry != v4_full_hash_cache_[threat_type].end()) {
175 // Case 1.
176 const SBCachedFullHashResult& cache_result = entry->second;
177
178 const SBFullHashResult* found_full_hash = nullptr;
179 for (const SBFullHashResult& hash_result : cache_result.full_hashes) {
180 if (SBFullHashEqual(full_hash, hash_result.hash)) {
181 found_full_hash = &hash_result;
182 break;
183 }
184 }
185
186 if (found_full_hash) {
187 // Case a.
188 if (found_full_hash->cache_expire_after > now) {
189 // Case i.
190 cached_results->push_back(*found_full_hash);
191 } else {
192 // Case ii.
193 prefixes_needing_reqs->push_back(full_hash.prefix);
194 }
195 } else {
196 // Case b.
197 if (cache_result.expire_after > now) {
198 // Case i.
199 } else {
200 // Case ii.
201 prefixes_needing_reqs->push_back(full_hash.prefix);
202 }
203 }
204 } else {
205 // Case 2.
206 prefixes_needing_reqs->push_back(full_hash.prefix);
207 }
208 }
209
210 // Multiple full hashes could share a prefix, remove duplicates.
211 std::sort(prefixes_needing_reqs->begin(), prefixes_needing_reqs->end());
212 prefixes_needing_reqs->erase(std::unique(prefixes_needing_reqs->begin(),
213 prefixes_needing_reqs->end()), prefixes_needing_reqs->end());
214 }
215
119 void SafeBrowsingDatabaseManager::HandleGetHashesWithApisResults( 216 void SafeBrowsingDatabaseManager::HandleGetHashesWithApisResults(
120 SafeBrowsingApiCheck* check, 217 SafeBrowsingApiCheck* check,
121 const std::vector<SBFullHashResult>& full_hash_results, 218 const std::vector<SBFullHashResult>& full_hash_results,
122 const base::Time& negative_cache_expire) { 219 const base::Time& negative_cache_expire) {
123 DCHECK_CURRENTLY_ON(BrowserThread::IO); 220 DCHECK_CURRENTLY_ON(BrowserThread::IO);
124 DCHECK(check); 221 DCHECK(check);
125 222
126 // If the time is uninitialized, don't cache the results. 223 // If the time is uninitialized, don't cache the results.
127 if (!negative_cache_expire.is_null()) { 224 if (!negative_cache_expire.is_null()) {
128 // Cache the results. 225 // Cache the results.
129 // Create or reset all cached results for this prefix. 226 // Create or reset all cached results for this prefix.
130 for (const SBPrefix& prefix : check->prefixes()) { 227 for (const SBPrefix& prefix : check->prefixes()) {
131 api_cache_[prefix] = SBCachedFullHashResult(negative_cache_expire); 228 v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE][prefix] =
229 SBCachedFullHashResult(negative_cache_expire);
132 } 230 }
133 // Insert any full hash hits. Note that there may be one, multiple, or no 231 // Insert any full hash hits. Note that there may be one, multiple, or no
134 // full hashes for any given prefix. 232 // full hashes for any given prefix.
135 for (const SBFullHashResult& result : full_hash_results) { 233 for (const SBFullHashResult& result : full_hash_results) {
136 api_cache_[result.hash.prefix].full_hashes.push_back(result); 234 v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE][result.hash.prefix].
235 full_hashes.push_back(result);
137 } 236 }
138 } 237 }
139 238
140 // If the check is not in |api_checks_| then the request was cancelled by the 239 // If the check is not in |api_checks_| then the request was cancelled by the
141 // client. 240 // client.
142 ApiCheckSet::iterator it = api_checks_.find(check); 241 ApiCheckSet::iterator it = api_checks_.find(check);
143 if (it == api_checks_.end()) 242 if (it == api_checks_.end())
144 return; 243 return;
145 244
146 ThreatMetadata md; 245 ThreatMetadata md;
147 // Merge the metadata from all matching results. 246 // Merge the metadata from all matching results.
148 // TODO(kcarattini): This is O(N^2). Look at improving performance by 247 // Note: A full hash may have a result in both the cached results (from
149 // using a map, sorting or doing binary search etc.. 248 // its own cache lookup) and in the server results (if another full hash
150 for (const SBFullHashResult& result : full_hash_results) { 249 // with the same prefix needed to request results from the server). In this
151 for (const SBFullHash& full_hash : check->full_hashes()) { 250 // unlikely case, the two results' metadata will be merged.
152 if (SBFullHashEqual(full_hash, result.hash)) { 251 PopulateApiMetadataResult(full_hash_results, check->full_hashes(), &md);
153 md.api_permissions.insert(md.api_permissions.end(), 252 PopulateApiMetadataResult(check->cached_results(), check->full_hashes(), &md);
154 result.metadata.api_permissions.begin(),
155 result.metadata.api_permissions.end());
156 break;
157 }
158 }
159 }
160 253
161 check->client()->OnCheckApiBlacklistUrlResult(check->url(), md); 254 check->client()->OnCheckApiBlacklistUrlResult(check->url(), md);
162 api_checks_.erase(it); 255 api_checks_.erase(it);
163 delete check; 256 delete check;
164 } 257 }
165 258
259 // TODO(kcarattini): This is O(N^2). Look at improving performance by
260 // using a map, sorting or doing binary search etc..
261 void SafeBrowsingDatabaseManager::PopulateApiMetadataResult(
262 const std::vector<SBFullHashResult>& results,
263 const std::vector<SBFullHash>& full_hashes,
264 ThreatMetadata* md) {
265 DCHECK(md);
266 for (const SBFullHashResult& result : results) {
267 for (const SBFullHash& full_hash : full_hashes) {
268 if (SBFullHashEqual(full_hash, result.hash)) {
269 md->api_permissions.insert(md->api_permissions.end(),
270 result.metadata.api_permissions.begin(),
271 result.metadata.api_permissions.end());
272 break;
273 }
274 }
275 }
276 }
277
166 SafeBrowsingDatabaseManager::SafeBrowsingApiCheck::SafeBrowsingApiCheck( 278 SafeBrowsingDatabaseManager::SafeBrowsingApiCheck::SafeBrowsingApiCheck(
167 const GURL& url, const std::vector<SBPrefix>& prefixes, 279 const GURL& url,
168 const std::vector<SBFullHash>& full_hashes, Client* client) 280 const std::vector<SBPrefix>& prefixes,
281 const std::vector<SBFullHash>& full_hashes,
282 const std::vector<SBFullHashResult>& cached_results,
283 Client* client)
169 : url_(url), prefixes_(prefixes), full_hashes_(full_hashes), 284 : url_(url), prefixes_(prefixes), full_hashes_(full_hashes),
170 client_(client) { 285 cached_results_(cached_results), client_(client) {
171 } 286 }
172 287
173 SafeBrowsingDatabaseManager::SafeBrowsingApiCheck::~SafeBrowsingApiCheck() { 288 SafeBrowsingDatabaseManager::SafeBrowsingApiCheck::~SafeBrowsingApiCheck() {
174 } 289 }
175 290
176 } // namespace safe_browsing 291 } // namespace safe_browsing
OLDNEW
« no previous file with comments | « components/safe_browsing_db/database_manager.h ('k') | components/safe_browsing_db/database_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698