Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/safe_browsing/database_manager.h" | 5 #include "chrome/browser/safe_browsing/database_manager.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/callback.h" | 9 #include "base/callback.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 #include "chrome/common/chrome_paths.h" | 28 #include "chrome/common/chrome_paths.h" |
| 29 #include "chrome/common/chrome_switches.h" | 29 #include "chrome/common/chrome_switches.h" |
| 30 #include "chrome/common/url_constants.h" | 30 #include "chrome/common/url_constants.h" |
| 31 #include "content/public/browser/browser_thread.h" | 31 #include "content/public/browser/browser_thread.h" |
| 32 #include "content/public/browser/notification_service.h" | 32 #include "content/public/browser/notification_service.h" |
| 33 | 33 |
| 34 using content::BrowserThread; | 34 using content::BrowserThread; |
| 35 | 35 |
| 36 namespace { | 36 namespace { |
| 37 | 37 |
| 38 // When download url check takes this long, client's callback will be called | 38 // Timeout for match checks, e.g. download URLs, hashes. |
| 39 // without waiting for the result. | 39 const int kCheckTimeoutMs = 10000; |
| 40 const int64 kDownloadUrlCheckTimeoutMs = 10000; | |
| 41 | |
| 42 // Similar to kDownloadUrlCheckTimeoutMs, but for download hash checks. | |
| 43 const int64 kDownloadHashCheckTimeoutMs = 10000; | |
| 44 | 40 |
| 45 // Records disposition information about the check. |hit| should be | 41 // Records disposition information about the check. |hit| should be |
| 46 // |true| if there were any prefix hits in |full_hashes|. | 42 // |true| if there were any prefix hits in |full_hashes|. |
| 47 void RecordGetHashCheckStatus( | 43 void RecordGetHashCheckStatus( |
| 48 bool hit, | 44 bool hit, |
| 49 bool is_download, | 45 safe_browsing_util::ListType check_type, |
| 50 const std::vector<SBFullHashResult>& full_hashes) { | 46 const std::vector<SBFullHashResult>& full_hashes) { |
| 51 SafeBrowsingProtocolManager::ResultType result; | 47 SafeBrowsingProtocolManager::ResultType result; |
| 52 if (full_hashes.empty()) { | 48 if (full_hashes.empty()) { |
| 53 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY; | 49 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY; |
| 54 } else if (hit) { | 50 } else if (hit) { |
| 55 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT; | 51 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT; |
| 56 } else { | 52 } else { |
| 57 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS; | 53 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS; |
| 58 } | 54 } |
| 55 bool is_download = check_type == safe_browsing_util::BINURL || | |
| 56 check_type == safe_browsing_util::BINHASH; | |
| 59 SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result); | 57 SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result); |
| 60 } | 58 } |
| 61 | 59 |
| 62 } // namespace | 60 } // namespace |
| 63 | 61 |
| 64 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck() | 62 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck( |
| 65 : full_hash(NULL), | 63 safe_browsing_util::ListType check_type) |
| 66 client(NULL), | 64 : client(NULL), |
| 67 need_get_hash(false), | 65 need_get_hash(false), |
| 68 threat_type(SB_THREAT_TYPE_SAFE), | 66 check_type(check_type), |
| 69 is_download(false), | |
| 70 timeout_factory_(NULL) { | 67 timeout_factory_(NULL) { |
| 71 } | 68 } |
| 72 | 69 |
| 73 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {} | 70 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {} |
| 74 | 71 |
| 72 // Gets the max threat type from a map of entity -> threat type. If all | |
| 73 // entities are safe then this will be SB_THREAT_TYPE_SAFE. | |
| 74 // | |
| 75 // This is really just a semi-arbitrary way to choose a single threat type from | |
| 76 // many. Under normal circumstances there will only be one type, and SAFE | |
| 77 // threats will be filtered out. | |
| 78 template<typename T> | |
| 79 SBThreatType GetMaxThreatType(const std::map<T, SBThreatType>& threats) { | |
| 80 SBThreatType max = SB_THREAT_TYPE_SAFE; | |
| 81 for (typename std::map<T, SBThreatType>::const_iterator it = threats.begin(); | |
| 82 it != threats.end(); ++it) { | |
| 83 if (it->second > max) | |
| 84 max = it->second; | |
| 85 } | |
| 86 return max; | |
| 87 } | |
| 88 | |
| 75 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult( | 89 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult( |
| 76 const SafeBrowsingCheck& check) { | 90 const SafeBrowsingCheck& check) { |
| 77 if (!check.urls.empty()) { | 91 if (!check.urls.empty()) { |
| 78 | 92 DCHECK(check.full_hashes.empty()); |
| 79 DCHECK(!check.full_hash.get()); | 93 switch (check.check_type) { |
| 80 if (!check.is_download) { | 94 case safe_browsing_util::MALWARE: |
| 81 DCHECK_EQ(1U, check.urls.size()); | 95 case safe_browsing_util::PHISH: |
| 82 OnCheckBrowseUrlResult(check.urls[0], check.threat_type); | 96 DCHECK_EQ(1U, check.urls.size()); |
| 83 } else { | 97 OnCheckBrowseUrlResult(check.urls[0], |
| 84 OnCheckDownloadUrlResult(check.urls, check.threat_type); | 98 GetMaxThreatType(check.url_threats)); |
|
Scott Hess - ex-Googler
2013/01/11 23:44:05
If url_threats were a parallel vector pre-filled w
not at google - send to devlin
2013/01/14 23:00:55
Done.
| |
| 99 break; | |
| 100 case safe_browsing_util::BINURL: | |
| 101 OnCheckDownloadUrlResult(check.urls, | |
| 102 GetMaxThreatType(check.url_threats)); | |
|
Scott Hess - ex-Googler
2013/01/11 23:44:05
And this would be *max_element(url_threats.begin()
not at google - send to devlin
2013/01/14 23:00:55
Done.
| |
| 103 break; | |
| 104 default: | |
| 105 NOTREACHED(); | |
| 85 } | 106 } |
| 86 } else if (check.full_hash.get()) { | 107 } else if (!check.full_hashes.empty()) { |
| 87 OnCheckDownloadHashResult( | 108 switch (check.check_type) { |
| 88 safe_browsing_util::SBFullHashToString(*check.full_hash), | 109 case safe_browsing_util::BINHASH: |
| 89 check.threat_type); | 110 DCHECK_EQ(1u, check.full_hashes.size()); |
| 111 OnCheckDownloadHashResult( | |
| 112 safe_browsing_util::SBFullHashToString(check.full_hashes[0]), | |
| 113 GetMaxThreatType(check.full_hash_threats)); | |
|
Scott Hess - ex-Googler
2013/01/11 23:44:05
Likewise here, just a different vector.
not at google - send to devlin
2013/01/14 23:00:55
Done.
| |
| 114 break; | |
| 115 default: | |
| 116 NOTREACHED(); | |
| 117 } | |
| 90 } else { | 118 } else { |
| 91 NOTREACHED(); | 119 NOTREACHED(); |
| 92 } | 120 } |
| 93 } | 121 } |
| 94 | 122 |
| 95 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager( | 123 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager( |
| 96 const scoped_refptr<SafeBrowsingService>& service) | 124 const scoped_refptr<SafeBrowsingService>& service) |
| 97 : sb_service_(service), | 125 : sb_service_(service), |
| 98 database_(NULL), | 126 database_(NULL), |
| 99 enabled_(false), | 127 enabled_(false), |
| 100 enable_download_protection_(false), | 128 enable_download_protection_(false), |
| 101 enable_csd_whitelist_(false), | 129 enable_csd_whitelist_(false), |
| 102 enable_download_whitelist_(false), | 130 enable_download_whitelist_(false), |
| 103 update_in_progress_(false), | 131 update_in_progress_(false), |
| 104 database_update_in_progress_(false), | 132 database_update_in_progress_(false), |
| 105 closing_database_(false), | 133 closing_database_(false), |
| 106 download_urlcheck_timeout_ms_(kDownloadUrlCheckTimeoutMs), | 134 download_url_check_timeout_( |
| 107 download_hashcheck_timeout_ms_(kDownloadHashCheckTimeoutMs) { | 135 base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)), |
| 136 download_hash_check_timeout_( | |
| 137 base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) { | |
|
Scott Hess - ex-Googler
2013/01/11 23:44:05
If they're going to be the same, do they need to b
not at google - send to devlin
2013/01/14 23:00:55
No idea, I assumed it was this way for some good r
| |
| 108 DCHECK(sb_service_ != NULL); | 138 DCHECK(sb_service_ != NULL); |
| 109 | 139 |
| 110 CommandLine* cmdline = CommandLine::ForCurrentProcess(); | 140 CommandLine* cmdline = CommandLine::ForCurrentProcess(); |
| 111 enable_download_protection_ = | 141 enable_download_protection_ = |
| 112 !cmdline->HasSwitch(switches::kSbDisableDownloadProtection); | 142 !cmdline->HasSwitch(switches::kSbDisableDownloadProtection); |
| 113 | 143 |
| 114 // We only download the csd-whitelist if client-side phishing detection is | 144 // We only download the csd-whitelist if client-side phishing detection is |
| 115 // enabled. | 145 // enabled. |
| 116 enable_csd_whitelist_ = | 146 enable_csd_whitelist_ = |
| 117 !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection); | 147 !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection); |
| 118 | 148 |
| 119 // TODO(noelutz): remove this boolean variable since it should always be true | 149 // TODO(noelutz): remove this boolean variable since it should always be true |
| 120 // if SafeBrowsing is enabled. Unfortunately, we have no test data for this | 150 // if SafeBrowsing is enabled. Unfortunately, we have no test data for this |
| 121 // list right now. This means that we need to be able to disable this list | 151 // list right now. This means that we need to be able to disable this list |
| 122 // for the SafeBrowsing test to pass. | 152 // for the SafeBrowsing test to pass. |
| 123 enable_download_whitelist_ = enable_csd_whitelist_; | 153 enable_download_whitelist_ = enable_csd_whitelist_; |
| 124 | |
| 125 } | 154 } |
| 126 | 155 |
| 127 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() { | 156 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() { |
| 128 // We should have already been shut down. If we're still enabled, then the | 157 // We should have already been shut down. If we're still enabled, then the |
| 129 // database isn't going to be closed properly, which could lead to corruption. | 158 // database isn't going to be closed properly, which could lead to corruption. |
| 130 DCHECK(!enabled_); | 159 DCHECK(!enabled_); |
| 131 } | 160 } |
| 132 | 161 |
| 133 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const { | 162 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const { |
| 134 return url.SchemeIs(chrome::kFtpScheme) || | 163 return url.SchemeIs(chrome::kFtpScheme) || |
| 135 url.SchemeIs(chrome::kHttpScheme) || | 164 url.SchemeIs(chrome::kHttpScheme) || |
| 136 url.SchemeIs(chrome::kHttpsScheme); | 165 url.SchemeIs(chrome::kHttpsScheme); |
| 137 } | 166 } |
| 138 | 167 |
| 139 bool SafeBrowsingDatabaseManager::CheckDownloadUrl( | 168 bool SafeBrowsingDatabaseManager::CheckDownloadUrl( |
| 140 const std::vector<GURL>& url_chain, | 169 const std::vector<GURL>& url_chain, |
| 141 Client* client) { | 170 Client* client) { |
| 142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 143 if (!enabled_ || !enable_download_protection_) | 172 if (!enabled_ || !enable_download_protection_) |
| 144 return true; | 173 return true; |
| 145 | 174 |
| 146 // We need to check the database for url prefix, and later may fetch the url | 175 // We need to check the database for url prefix, and later may fetch the url |
| 147 // from the safebrowsing backends. These need to be asynchronous. | 176 // from the safebrowsing backends. These need to be asynchronous. |
| 148 SafeBrowsingCheck* check = new SafeBrowsingCheck(); | 177 SafeBrowsingCheck* check = new SafeBrowsingCheck(safe_browsing_util::BINURL); |
| 149 check->urls = url_chain; | 178 check->urls = url_chain; |
| 150 StartDownloadCheck( | 179 StartSafeBrowsingCheck( |
| 151 check, | 180 check, |
| 152 client, | 181 client, |
| 153 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this, | 182 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this, |
| 154 check), | 183 check), |
| 155 download_urlcheck_timeout_ms_); | 184 download_url_check_timeout_); |
| 156 return false; | 185 return false; |
| 157 } | 186 } |
| 158 | 187 |
| 159 bool SafeBrowsingDatabaseManager::CheckDownloadHash( | 188 bool SafeBrowsingDatabaseManager::CheckDownloadHash( |
| 160 const std::string& full_hash, | 189 const std::string& full_hash, |
| 161 Client* client) { | 190 Client* client) { |
| 162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 163 DCHECK(!full_hash.empty()); | 192 DCHECK(!full_hash.empty()); |
| 164 if (!enabled_ || !enable_download_protection_ || full_hash.empty()) | 193 if (!enabled_ || !enable_download_protection_ || full_hash.empty()) |
| 165 return true; | 194 return true; |
| 166 | 195 |
| 167 // We need to check the database for url prefix, and later may fetch the url | 196 // We need to check the database for url prefix, and later may fetch the url |
| 168 // from the safebrowsing backends. These need to be asynchronous. | 197 // from the safebrowsing backends. These need to be asynchronous. |
| 169 SafeBrowsingCheck* check = new SafeBrowsingCheck(); | 198 SafeBrowsingCheck* check = new SafeBrowsingCheck(safe_browsing_util::BINHASH); |
| 170 check->full_hash.reset(new SBFullHash); | 199 check->full_hashes.push_back( |
| 171 safe_browsing_util::StringToSBFullHash(full_hash, check->full_hash.get()); | 200 safe_browsing_util::StringToSBFullHash(full_hash)); |
| 172 StartDownloadCheck( | 201 StartSafeBrowsingCheck( |
| 173 check, | 202 check, |
| 174 client, | 203 client, |
| 175 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadHashOnSBThread,this, | 204 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadHashOnSBThread,this, |
| 176 check), | 205 check), |
| 177 download_hashcheck_timeout_ms_); | 206 download_hash_check_timeout_); |
| 178 return false; | 207 return false; |
| 179 } | 208 } |
| 180 | 209 |
| 181 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) { | 210 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) { |
| 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 183 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) { | 212 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) { |
| 184 // There is something funky going on here -- for example, perhaps the user | 213 // There is something funky going on here -- for example, perhaps the user |
| 185 // has not restarted since enabling metrics reporting, so we haven't | 214 // has not restarted since enabling metrics reporting, so we haven't |
| 186 // enabled the csd whitelist yet. Just to be safe we return true in this | 215 // enabled the csd whitelist yet. Just to be safe we return true in this |
| 187 // case. | 216 // case. |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 213 if (!enabled_) | 242 if (!enabled_) |
| 214 return true; | 243 return true; |
| 215 | 244 |
| 216 if (!CanCheckUrl(url)) | 245 if (!CanCheckUrl(url)) |
| 217 return true; | 246 return true; |
| 218 | 247 |
| 219 const base::TimeTicks start = base::TimeTicks::Now(); | 248 const base::TimeTicks start = base::TimeTicks::Now(); |
| 220 if (!MakeDatabaseAvailable()) { | 249 if (!MakeDatabaseAvailable()) { |
| 221 QueuedCheck check; | 250 QueuedCheck check; |
| 251 check.check_type = safe_browsing_util::MALWARE; // or PHISH | |
| 222 check.client = client; | 252 check.client = client; |
| 223 check.url = url; | 253 check.url = url; |
| 224 check.start = start; | 254 check.start = start; |
| 225 queued_checks_.push_back(check); | 255 queued_checks_.push_back(check); |
| 226 return false; | 256 return false; |
| 227 } | 257 } |
| 228 | 258 |
| 229 std::string list; | 259 std::string list; |
| 230 std::vector<SBPrefix> prefix_hits; | 260 std::vector<SBPrefix> prefix_hits; |
| 231 std::vector<SBFullHashResult> full_hits; | 261 std::vector<SBFullHashResult> full_hits; |
| 232 | 262 |
| 233 bool prefix_match = | 263 bool prefix_match = |
| 234 database_->ContainsBrowseUrl(url, &list, &prefix_hits, &full_hits, | 264 database_->ContainsBrowseUrl(url, &list, &prefix_hits, &full_hits, |
| 235 sb_service_->protocol_manager()->last_update()); | 265 sb_service_->protocol_manager()->last_update()); |
| 236 | 266 |
| 237 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start); | 267 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start); |
| 238 | 268 |
| 239 if (!prefix_match) | 269 if (!prefix_match) |
| 240 return true; // URL is okay. | 270 return true; // URL is okay. |
| 241 | 271 |
| 242 // Needs to be asynchronous, since we could be in the constructor of a | 272 // Needs to be asynchronous, since we could be in the constructor of a |
| 243 // ResourceDispatcherHost event handler which can't pause there. | 273 // ResourceDispatcherHost event handler which can't pause there. |
| 244 SafeBrowsingCheck* check = new SafeBrowsingCheck(); | 274 SafeBrowsingCheck* check = |
| 275 new SafeBrowsingCheck(safe_browsing_util::MALWARE); // or PHISH | |
| 245 check->urls.push_back(url); | 276 check->urls.push_back(url); |
| 246 check->client = client; | 277 check->client = client; |
| 247 check->threat_type = SB_THREAT_TYPE_SAFE; | |
| 248 check->is_download = false; | |
| 249 check->need_get_hash = full_hits.empty(); | 278 check->need_get_hash = full_hits.empty(); |
| 250 check->prefix_hits.swap(prefix_hits); | 279 check->prefix_hits.swap(prefix_hits); |
| 251 check->full_hits.swap(full_hits); | 280 check->full_hits.swap(full_hits); |
| 252 checks_.insert(check); | 281 checks_.insert(check); |
| 253 | 282 |
| 254 BrowserThread::PostTask( | 283 BrowserThread::PostTask( |
| 255 BrowserThread::IO, FROM_HERE, | 284 BrowserThread::IO, FROM_HERE, |
| 256 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); | 285 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); |
| 257 | 286 |
| 258 return false; | 287 return false; |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 396 if (!enabled_) | 425 if (!enabled_) |
| 397 return; | 426 return; |
| 398 | 427 |
| 399 enabled_ = false; | 428 enabled_ = false; |
| 400 | 429 |
| 401 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. | 430 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. |
| 402 // If we don't do this here we may fail to close the database below. | 431 // If we don't do this here we may fail to close the database below. |
| 403 while (!queued_checks_.empty()) { | 432 while (!queued_checks_.empty()) { |
| 404 QueuedCheck queued = queued_checks_.front(); | 433 QueuedCheck queued = queued_checks_.front(); |
| 405 if (queued.client) { | 434 if (queued.client) { |
| 406 SafeBrowsingCheck sb_check; | 435 SafeBrowsingCheck sb_check(queued.check_type); |
| 407 sb_check.urls.push_back(queued.url); | 436 sb_check.urls.push_back(queued.url); |
| 408 sb_check.client = queued.client; | 437 sb_check.client = queued.client; |
| 409 sb_check.threat_type = SB_THREAT_TYPE_SAFE; | |
| 410 queued.client->OnSafeBrowsingResult(sb_check); | 438 queued.client->OnSafeBrowsingResult(sb_check); |
| 411 } | 439 } |
| 412 queued_checks_.pop_front(); | 440 queued_checks_.pop_front(); |
| 413 } | 441 } |
| 414 | 442 |
| 415 // Close the database. We don't simply DeleteSoon() because if a close is | 443 // Close the database. We don't simply DeleteSoon() because if a close is |
| 416 // already pending, we'll double-free, and we don't set |database_| to NULL | 444 // already pending, we'll double-free, and we don't set |database_| to NULL |
| 417 // because if there is still anything running on the db thread, it could | 445 // because if there is still anything running on the db thread, it could |
| 418 // create a new database object (via GetDatabase()) that would then leak. | 446 // create a new database object (via GetDatabase()) that would then leak. |
| 419 CloseDatabase(); | 447 CloseDatabase(); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 431 safe_browsing_thread_.reset(); | 459 safe_browsing_thread_.reset(); |
| 432 } | 460 } |
| 433 | 461 |
| 434 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. | 462 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. |
| 435 // We have to do this after the db thread returns because methods on it can | 463 // We have to do this after the db thread returns because methods on it can |
| 436 // have copies of these pointers, so deleting them might lead to accessing | 464 // have copies of these pointers, so deleting them might lead to accessing |
| 437 // garbage. | 465 // garbage. |
| 438 for (CurrentChecks::iterator it = checks_.begin(); | 466 for (CurrentChecks::iterator it = checks_.begin(); |
| 439 it != checks_.end(); ++it) { | 467 it != checks_.end(); ++it) { |
| 440 SafeBrowsingCheck* check = *it; | 468 SafeBrowsingCheck* check = *it; |
| 441 if (check->client) { | 469 if (check->client) |
| 442 check->threat_type = SB_THREAT_TYPE_SAFE; | |
| 443 check->client->OnSafeBrowsingResult(*check); | 470 check->client->OnSafeBrowsingResult(*check); |
| 444 } | |
| 445 } | 471 } |
| 446 STLDeleteElements(&checks_); | 472 STLDeleteElements(&checks_); |
| 447 | 473 |
| 448 gethash_requests_.clear(); | 474 gethash_requests_.clear(); |
| 449 } | 475 } |
| 450 | 476 |
| 451 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const { | 477 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const { |
| 452 base::AutoLock lock(database_lock_); | 478 base::AutoLock lock(database_lock_); |
| 453 return !closing_database_ && (database_ != NULL); | 479 return !closing_database_ && (database_ != NULL); |
| 454 } | 480 } |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 554 GetHashRequestors requestors; | 580 GetHashRequestors requestors; |
| 555 requestors.push_back(check); | 581 requestors.push_back(check); |
| 556 gethash_requests_[prefix] = requestors; | 582 gethash_requests_[prefix] = requestors; |
| 557 } | 583 } |
| 558 | 584 |
| 559 // Reset the start time so that we can measure the network time without the | 585 // Reset the start time so that we can measure the network time without the |
| 560 // database time. | 586 // database time. |
| 561 check->start = base::TimeTicks::Now(); | 587 check->start = base::TimeTicks::Now(); |
| 562 // Note: If |this| is deleted or stopped, the protocol_manager will | 588 // Note: If |this| is deleted or stopped, the protocol_manager will |
| 563 // be destroyed as well - hence it's OK to do unretained in this case. | 589 // be destroyed as well - hence it's OK to do unretained in this case. |
| 590 bool is_download = check->check_type == safe_browsing_util::BINURL || | |
| 591 check->check_type == safe_browsing_util::BINHASH; | |
| 564 sb_service_->protocol_manager()->GetFullHash( | 592 sb_service_->protocol_manager()->GetFullHash( |
| 565 check->prefix_hits, | 593 check->prefix_hits, |
| 566 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults, | 594 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults, |
| 567 base::Unretained(this), | 595 base::Unretained(this), |
| 568 check), | 596 check), |
| 569 check->is_download); | 597 is_download); |
| 570 } else { | 598 } else { |
| 571 // We may have cached results for previous GetHash queries. Since | 599 // We may have cached results for previous GetHash queries. Since |
| 572 // this data comes from cache, don't histogram hits. | 600 // this data comes from cache, don't histogram hits. |
| 573 HandleOneCheck(check, check->full_hits); | 601 HandleOneCheck(check, check->full_hits); |
| 574 } | 602 } |
| 575 } | 603 } |
| 576 | 604 |
| 577 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase( | 605 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase( |
| 578 GetChunksCallback callback) { | 606 GetChunksCallback callback) { |
| 579 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); | 607 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 623 // below will add the check back to the queue, and we'll infinite-loop. | 651 // below will add the check back to the queue, and we'll infinite-loop. |
| 624 DCHECK(DatabaseAvailable()); | 652 DCHECK(DatabaseAvailable()); |
| 625 while (!queued_checks_.empty()) { | 653 while (!queued_checks_.empty()) { |
| 626 QueuedCheck check = queued_checks_.front(); | 654 QueuedCheck check = queued_checks_.front(); |
| 627 DCHECK(!check.start.is_null()); | 655 DCHECK(!check.start.is_null()); |
| 628 HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start); | 656 HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start); |
| 629 // If CheckUrl() determines the URL is safe immediately, it doesn't call the | 657 // If CheckUrl() determines the URL is safe immediately, it doesn't call the |
| 630 // client's handler function (because normally it's being directly called by | 658 // client's handler function (because normally it's being directly called by |
| 631 // the client). Since we're not the client, we have to convey this result. | 659 // the client). Since we're not the client, we have to convey this result. |
| 632 if (check.client && CheckBrowseUrl(check.url, check.client)) { | 660 if (check.client && CheckBrowseUrl(check.url, check.client)) { |
| 633 SafeBrowsingCheck sb_check; | 661 SafeBrowsingCheck sb_check(check.check_type); |
| 634 sb_check.urls.push_back(check.url); | 662 sb_check.urls.push_back(check.url); |
| 635 sb_check.client = check.client; | 663 sb_check.client = check.client; |
| 636 sb_check.threat_type = SB_THREAT_TYPE_SAFE; | |
| 637 check.client->OnSafeBrowsingResult(sb_check); | 664 check.client->OnSafeBrowsingResult(sb_check); |
| 638 } | 665 } |
| 639 queued_checks_.pop_front(); | 666 queued_checks_.pop_front(); |
| 640 } | 667 } |
| 641 } | 668 } |
| 642 | 669 |
| 643 void SafeBrowsingDatabaseManager::AddDatabaseChunks( | 670 void SafeBrowsingDatabaseManager::AddDatabaseChunks( |
| 644 const std::string& list_name, SBChunkList* chunks, | 671 const std::string& list_name, SBChunkList* chunks, |
| 645 AddChunksCallback callback) { | 672 AddChunksCallback callback) { |
| 646 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); | 673 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 731 const std::vector<SBPrefix>& prefixes, | 758 const std::vector<SBPrefix>& prefixes, |
| 732 const std::vector<SBFullHashResult>& full_hashes) { | 759 const std::vector<SBFullHashResult>& full_hashes) { |
| 733 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); | 760 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); |
| 734 GetDatabase()->CacheHashResults(prefixes, full_hashes); | 761 GetDatabase()->CacheHashResults(prefixes, full_hashes); |
| 735 } | 762 } |
| 736 | 763 |
| 737 void SafeBrowsingDatabaseManager::OnHandleGetHashResults( | 764 void SafeBrowsingDatabaseManager::OnHandleGetHashResults( |
| 738 SafeBrowsingCheck* check, | 765 SafeBrowsingCheck* check, |
| 739 const std::vector<SBFullHashResult>& full_hashes) { | 766 const std::vector<SBFullHashResult>& full_hashes) { |
| 740 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 767 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 741 bool is_download = check->is_download; | 768 safe_browsing_util::ListType check_type = check->check_type; |
| 742 SBPrefix prefix = check->prefix_hits[0]; | 769 SBPrefix prefix = check->prefix_hits[0]; |
| 743 GetHashRequests::iterator it = gethash_requests_.find(prefix); | 770 GetHashRequests::iterator it = gethash_requests_.find(prefix); |
| 744 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) { | 771 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) { |
| 745 const bool hit = HandleOneCheck(check, full_hashes); | 772 const bool hit = HandleOneCheck(check, full_hashes); |
| 746 RecordGetHashCheckStatus(hit, is_download, full_hashes); | 773 RecordGetHashCheckStatus(hit, check_type, full_hashes); |
| 747 return; | 774 return; |
| 748 } | 775 } |
| 749 | 776 |
| 750 // Call back all interested parties, noting if any has a hit. | 777 // Call back all interested parties, noting if any has a hit. |
| 751 GetHashRequestors& requestors = it->second; | 778 GetHashRequestors& requestors = it->second; |
| 752 bool hit = false; | 779 bool hit = false; |
| 753 for (GetHashRequestors::iterator r = requestors.begin(); | 780 for (GetHashRequestors::iterator r = requestors.begin(); |
| 754 r != requestors.end(); ++r) { | 781 r != requestors.end(); ++r) { |
| 755 if (HandleOneCheck(*r, full_hashes)) | 782 if (HandleOneCheck(*r, full_hashes)) |
| 756 hit = true; | 783 hit = true; |
| 757 } | 784 } |
| 758 RecordGetHashCheckStatus(hit, is_download, full_hashes); | 785 RecordGetHashCheckStatus(hit, check_type, full_hashes); |
| 759 | 786 |
| 760 gethash_requests_.erase(it); | 787 gethash_requests_.erase(it); |
| 761 } | 788 } |
| 762 | 789 |
| 763 bool SafeBrowsingDatabaseManager::HandleOneCheck( | 790 bool SafeBrowsingDatabaseManager::HandleOneCheck( |
| 764 SafeBrowsingCheck* check, | 791 SafeBrowsingCheck* check, |
| 765 const std::vector<SBFullHashResult>& full_hashes) { | 792 const std::vector<SBFullHashResult>& full_hashes) { |
| 766 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 793 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 767 DCHECK(check); | 794 DCHECK(check); |
| 768 | 795 |
| 769 // Always calculate the index, for recording hits. | 796 for (std::vector<GURL>::iterator it = check->urls.begin(); |
| 770 int index = -1; | 797 it != check->urls.end(); ++it) { |
| 771 if (!check->urls.empty()) { | 798 int index = safe_browsing_util::GetUrlHashIndex(*it, full_hashes); |
| 772 for (size_t i = 0; i < check->urls.size(); ++i) { | 799 if (index == -1) |
| 773 index = safe_browsing_util::GetUrlHashIndex(check->urls[i], full_hashes); | 800 continue; |
| 774 if (index != -1) | 801 SBThreatType threat = |
| 775 break; | 802 GetThreatTypeFromListname(full_hashes[index].list_name); |
| 776 } | 803 if (threat != SB_THREAT_TYPE_SAFE) |
| 777 } else { | 804 check->url_threats[*it] = threat; |
| 778 index = safe_browsing_util::GetHashIndex(*(check->full_hash), full_hashes); | 805 else |
| 806 NOTREACHED(); | |
| 779 } | 807 } |
| 780 | 808 |
| 781 // |client| is NULL if the request was cancelled. | 809 for (std::vector<SBFullHash>::iterator it = check->full_hashes.begin(); |
| 782 if (check->client) { | 810 it != check->full_hashes.end(); ++it) { |
| 783 check->threat_type = SB_THREAT_TYPE_SAFE; | 811 int index = safe_browsing_util::GetHashIndex(*it, full_hashes); |
| 784 if (index != -1) { | 812 if (index == -1) |
| 785 check->threat_type = GetThreatTypeFromListname( | 813 continue; |
| 786 full_hashes[index].list_name); | 814 SBThreatType threat = |
| 787 } | 815 GetThreatTypeFromListname(full_hashes[index].list_name); |
| 816 if (threat != SB_THREAT_TYPE_SAFE) | |
| 817 check->full_hash_threats[*it] = threat; | |
| 818 else | |
| 819 NOTREACHED(); | |
| 788 } | 820 } |
| 821 | |
| 789 SafeBrowsingCheckDone(check); | 822 SafeBrowsingCheckDone(check); |
| 790 return (index != -1); | 823 return check->url_threats.empty() && check->full_hash_threats.empty(); |
| 791 } | 824 } |
| 792 | 825 |
| 793 void SafeBrowsingDatabaseManager::CheckDownloadHashOnSBThread( | 826 void SafeBrowsingDatabaseManager::CheckDownloadHashOnSBThread( |
| 794 SafeBrowsingCheck* check) { | 827 SafeBrowsingCheck* check) { |
| 795 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); | 828 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); |
| 796 DCHECK(enable_download_protection_); | 829 DCHECK(enable_download_protection_); |
| 797 | 830 |
| 798 if (!database_->ContainsDownloadHashPrefix(check->full_hash->prefix)) { | 831 DCHECK_EQ(1u, check->full_hashes.size()); |
| 832 SBFullHash full_hash = check->full_hashes[0]; | |
| 833 | |
| 834 if (!database_->ContainsDownloadHashPrefix(full_hash.prefix)) { | |
| 799 // Good, we don't have hash for this url prefix. | 835 // Good, we don't have hash for this url prefix. |
| 800 check->threat_type = SB_THREAT_TYPE_SAFE; | |
| 801 BrowserThread::PostTask( | 836 BrowserThread::PostTask( |
| 802 BrowserThread::IO, FROM_HERE, | 837 BrowserThread::IO, FROM_HERE, |
| 803 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadHashDone, this, | 838 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadHashDone, this, |
| 804 check)); | 839 check)); |
| 805 return; | 840 return; |
| 806 } | 841 } |
| 807 | 842 |
| 808 check->need_get_hash = true; | 843 check->need_get_hash = true; |
| 809 check->prefix_hits.push_back(check->full_hash->prefix); | 844 check->prefix_hits.push_back(full_hash.prefix); |
| 810 BrowserThread::PostTask( | 845 BrowserThread::PostTask( |
| 811 BrowserThread::IO, FROM_HERE, | 846 BrowserThread::IO, FROM_HERE, |
| 812 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); | 847 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); |
| 813 } | 848 } |
| 814 | 849 |
| 815 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread( | 850 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread( |
| 816 SafeBrowsingCheck* check) { | 851 SafeBrowsingCheck* check) { |
| 817 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); | 852 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); |
| 818 DCHECK(enable_download_protection_); | 853 DCHECK(enable_download_protection_); |
| 819 | 854 |
| 820 std::vector<SBPrefix> prefix_hits; | 855 std::vector<SBPrefix> prefix_hits; |
| 821 | 856 |
| 822 if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) { | 857 if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) { |
| 823 // Good, we don't have hash for this url prefix. | 858 // Good, we don't have hash for this url prefix. |
| 824 check->threat_type = SB_THREAT_TYPE_SAFE; | |
| 825 BrowserThread::PostTask( | 859 BrowserThread::PostTask( |
| 826 BrowserThread::IO, FROM_HERE, | 860 BrowserThread::IO, FROM_HERE, |
| 827 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this, | 861 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this, |
| 828 check)); | 862 check)); |
| 829 return; | 863 return; |
| 830 } | 864 } |
| 831 | 865 |
| 832 check->need_get_hash = true; | 866 check->need_get_hash = true; |
| 833 check->prefix_hits.clear(); | 867 check->prefix_hits.clear(); |
| 834 check->prefix_hits = prefix_hits; | 868 check->prefix_hits = prefix_hits; |
| 835 BrowserThread::PostTask( | 869 BrowserThread::PostTask( |
| 836 BrowserThread::IO, FROM_HERE, | 870 BrowserThread::IO, FROM_HERE, |
| 837 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); | 871 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); |
| 838 } | 872 } |
| 839 | 873 |
| 840 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) { | 874 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) { |
| 841 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 875 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 842 DCHECK(check); | 876 DCHECK(check); |
| 843 | 877 |
| 844 if (!enabled_) | 878 if (!enabled_) |
| 845 return; | 879 return; |
| 846 | 880 |
| 847 DCHECK(checks_.find(check) != checks_.end()); | 881 DCHECK(checks_.find(check) != checks_.end()); |
| 848 DCHECK_EQ(check->threat_type, SB_THREAT_TYPE_SAFE); | |
| 849 if (check->client) { | 882 if (check->client) { |
| 850 check->client->OnSafeBrowsingResult(*check); | 883 check->client->OnSafeBrowsingResult(*check); |
| 851 check->client = NULL; | 884 check->client = NULL; |
| 852 } | 885 } |
| 853 } | 886 } |
| 854 | 887 |
| 855 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone( | 888 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone( |
| 856 SafeBrowsingCheck* check) { | 889 SafeBrowsingCheck* check) { |
| 857 DCHECK(enable_download_protection_); | 890 DCHECK(enable_download_protection_); |
| 858 SafeBrowsingCheckDone(check); | 891 SafeBrowsingCheckDone(check); |
| 859 } | 892 } |
| 860 | 893 |
| 861 void SafeBrowsingDatabaseManager::CheckDownloadHashDone( | 894 void SafeBrowsingDatabaseManager::CheckDownloadHashDone( |
| 862 SafeBrowsingCheck* check) { | 895 SafeBrowsingCheck* check) { |
| 863 DCHECK(enable_download_protection_); | 896 DCHECK(enable_download_protection_); |
| 864 SafeBrowsingCheckDone(check); | 897 SafeBrowsingCheckDone(check); |
| 865 } | 898 } |
| 866 | 899 |
| 867 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone( | 900 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone( |
| 868 SafeBrowsingCheck* check) { | 901 SafeBrowsingCheck* check) { |
| 869 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 902 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 870 DCHECK(check); | 903 DCHECK(check); |
| 871 | 904 |
| 872 if (!enabled_) | 905 if (!enabled_) |
| 873 return; | 906 return; |
| 874 | 907 |
| 875 VLOG(1) << "SafeBrowsingCheckDone: " << check->threat_type; | 908 VLOG(1) << "SafeBrowsingCheckDone: " << |
| 909 check->url_threats.size() << " URL hits, " << | |
| 910 check->full_hash_threats.size() << " hash hits"; | |
| 876 DCHECK(checks_.find(check) != checks_.end()); | 911 DCHECK(checks_.find(check) != checks_.end()); |
| 877 if (check->client) | 912 if (check->client) |
| 878 check->client->OnSafeBrowsingResult(*check); | 913 check->client->OnSafeBrowsingResult(*check); |
| 879 checks_.erase(check); | 914 checks_.erase(check); |
| 880 delete check; | 915 delete check; |
| 881 } | 916 } |
| 882 | 917 |
| 883 void SafeBrowsingDatabaseManager::StartDownloadCheck(SafeBrowsingCheck* check, | 918 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck( |
| 884 Client* client, | 919 SafeBrowsingCheck* check, |
| 885 const base::Closure& task, | 920 Client* client, |
| 886 int64 timeout_ms) { | 921 const base::Closure& task, |
| 887 | 922 const base::TimeDelta& timeout) { |
| 888 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 923 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 889 check->client = client; | 924 check->client = client; |
| 890 check->threat_type = SB_THREAT_TYPE_SAFE; | |
| 891 check->is_download = true; | |
| 892 check->timeout_factory_.reset( | 925 check->timeout_factory_.reset( |
| 893 new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this)); | 926 new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this)); |
| 894 checks_.insert(check); | 927 checks_.insert(check); |
| 895 | 928 |
| 896 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task); | 929 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task); |
| 897 | 930 |
| 898 MessageLoop::current()->PostDelayedTask(FROM_HERE, | 931 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| 899 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback, | 932 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback, |
| 900 check->timeout_factory_->GetWeakPtr(), check), | 933 check->timeout_factory_->GetWeakPtr(), check), |
| 901 base::TimeDelta::FromMilliseconds(timeout_ms)); | 934 timeout); |
| 902 } | 935 } |
| OLD | NEW |