| 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 } |
| 59 SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result); | 55 SafeBrowsingProtocolManager::RecordGetHashResult(check_type, result); |
| 60 } | 56 } |
| 61 | 57 |
| 62 } // namespace | 58 } // namespace |
| 63 | 59 |
| 64 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck() | 60 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck( |
| 65 : full_hash(NULL), | 61 safe_browsing_util::ListType check_type) |
| 66 client(NULL), | 62 : client(NULL), |
| 67 need_get_hash(false), | 63 need_get_hash(false), |
| 68 threat_type(SB_THREAT_TYPE_SAFE), | 64 check_type(check_type), |
| 69 is_download(false), | |
| 70 timeout_factory_(NULL) { | 65 timeout_factory_(NULL) { |
| 71 } | 66 } |
| 72 | 67 |
| 73 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {} | 68 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {} |
| 74 | 69 |
| 75 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult( | 70 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult( |
| 76 const SafeBrowsingCheck& check) { | 71 const SafeBrowsingCheck& check) { |
| 77 if (!check.urls.empty()) { | 72 if (!check.urls.empty()) { |
| 78 | 73 DCHECK(check.full_hashes.empty()); |
| 79 DCHECK(!check.full_hash.get()); | 74 switch (check.check_type) { |
| 80 if (!check.is_download) { | 75 case safe_browsing_util::MALWARE: |
| 81 DCHECK_EQ(1U, check.urls.size()); | 76 case safe_browsing_util::PHISH: |
| 82 OnCheckBrowseUrlResult(check.urls[0], check.threat_type); | 77 DCHECK_EQ(1U, check.urls.size()); |
| 83 } else { | 78 OnCheckBrowseUrlResult( |
| 84 OnCheckDownloadUrlResult(check.urls, check.threat_type); | 79 check.urls[0], |
| 80 check.url_threats.empty() ? SB_THREAT_TYPE_SAFE |
| 81 : check.url_threats.begin()->second); |
| 82 break; |
| 83 case safe_browsing_util::BINURL: |
| 84 OnCheckDownloadUrlResult( |
| 85 check.urls, |
| 86 check.url_threats.empty() ? SB_THREAT_TYPE_SAFE |
| 87 : SB_THREAT_TYPE_BINARY_MALWARE_URL); |
| 88 break; |
| 89 default: |
| 90 NOTREACHED(); |
| 85 } | 91 } |
| 86 } else if (check.full_hash.get()) { | 92 } else if (!check.full_hashes.empty()) { |
| 87 OnCheckDownloadHashResult( | 93 switch (check.check_type) { |
| 88 safe_browsing_util::SBFullHashToString(*check.full_hash), | 94 case safe_browsing_util::BINHASH: |
| 89 check.threat_type); | 95 DCHECK_EQ(1u, check.full_hashes.size()); |
| 96 OnCheckDownloadHashResult( |
| 97 safe_browsing_util::SBFullHashToString(check.full_hashes[0]), |
| 98 check.full_hash_threats.empty() |
| 99 ? SB_THREAT_TYPE_SAFE |
| 100 : SB_THREAT_TYPE_BINARY_MALWARE_HASH); |
| 101 break; |
| 102 default: |
| 103 NOTREACHED(); |
| 104 } |
| 90 } else { | 105 } else { |
| 91 NOTREACHED(); | 106 NOTREACHED(); |
| 92 } | 107 } |
| 93 } | 108 } |
| 94 | 109 |
| 95 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager( | 110 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager( |
| 96 const scoped_refptr<SafeBrowsingService>& service) | 111 const scoped_refptr<SafeBrowsingService>& service) |
| 97 : sb_service_(service), | 112 : sb_service_(service), |
| 98 database_(NULL), | 113 database_(NULL), |
| 99 enabled_(false), | 114 enabled_(false), |
| 100 enable_download_protection_(false), | 115 enable_download_protection_(false), |
| 101 enable_csd_whitelist_(false), | 116 enable_csd_whitelist_(false), |
| 102 enable_download_whitelist_(false), | 117 enable_download_whitelist_(false), |
| 103 update_in_progress_(false), | 118 update_in_progress_(false), |
| 104 database_update_in_progress_(false), | 119 database_update_in_progress_(false), |
| 105 closing_database_(false), | 120 closing_database_(false), |
| 106 download_urlcheck_timeout_ms_(kDownloadUrlCheckTimeoutMs), | 121 download_url_check_timeout_( |
| 107 download_hashcheck_timeout_ms_(kDownloadHashCheckTimeoutMs) { | 122 base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)), |
| 123 download_hash_check_timeout_( |
| 124 base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) { |
| 108 DCHECK(sb_service_ != NULL); | 125 DCHECK(sb_service_ != NULL); |
| 109 | 126 |
| 110 CommandLine* cmdline = CommandLine::ForCurrentProcess(); | 127 CommandLine* cmdline = CommandLine::ForCurrentProcess(); |
| 111 enable_download_protection_ = | 128 enable_download_protection_ = |
| 112 !cmdline->HasSwitch(switches::kSbDisableDownloadProtection); | 129 !cmdline->HasSwitch(switches::kSbDisableDownloadProtection); |
| 113 | 130 |
| 114 // We only download the csd-whitelist if client-side phishing detection is | 131 // We only download the csd-whitelist if client-side phishing detection is |
| 115 // enabled. | 132 // enabled. |
| 116 enable_csd_whitelist_ = | 133 enable_csd_whitelist_ = |
| 117 !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection); | 134 !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection); |
| 118 | 135 |
| 119 // TODO(noelutz): remove this boolean variable since it should always be true | 136 // 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 | 137 // 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 | 138 // list right now. This means that we need to be able to disable this list |
| 122 // for the SafeBrowsing test to pass. | 139 // for the SafeBrowsing test to pass. |
| 123 enable_download_whitelist_ = enable_csd_whitelist_; | 140 enable_download_whitelist_ = enable_csd_whitelist_; |
| 124 | |
| 125 } | 141 } |
| 126 | 142 |
| 127 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() { | 143 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() { |
| 128 // We should have already been shut down. If we're still enabled, then the | 144 // 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. | 145 // database isn't going to be closed properly, which could lead to corruption. |
| 130 DCHECK(!enabled_); | 146 DCHECK(!enabled_); |
| 131 } | 147 } |
| 132 | 148 |
| 133 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const { | 149 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const { |
| 134 return url.SchemeIs(chrome::kFtpScheme) || | 150 return url.SchemeIs(chrome::kFtpScheme) || |
| 135 url.SchemeIs(chrome::kHttpScheme) || | 151 url.SchemeIs(chrome::kHttpScheme) || |
| 136 url.SchemeIs(chrome::kHttpsScheme); | 152 url.SchemeIs(chrome::kHttpsScheme); |
| 137 } | 153 } |
| 138 | 154 |
| 139 bool SafeBrowsingDatabaseManager::CheckDownloadUrl( | 155 bool SafeBrowsingDatabaseManager::CheckDownloadUrl( |
| 140 const std::vector<GURL>& url_chain, | 156 const std::vector<GURL>& url_chain, |
| 141 Client* client) { | 157 Client* client) { |
| 142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 143 if (!enabled_ || !enable_download_protection_) | 159 if (!enabled_ || !enable_download_protection_) |
| 144 return true; | 160 return true; |
| 145 | 161 |
| 146 // We need to check the database for url prefix, and later may fetch the url | 162 // 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. | 163 // from the safebrowsing backends. These need to be asynchronous. |
| 148 SafeBrowsingCheck* check = new SafeBrowsingCheck(); | 164 SafeBrowsingCheck* check = new SafeBrowsingCheck(safe_browsing_util::BINURL); |
| 149 check->urls = url_chain; | 165 check->urls = url_chain; |
| 150 StartDownloadCheck( | 166 StartSafeBrowsingCheck( |
| 151 check, | 167 check, |
| 152 client, | 168 client, |
| 153 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this, | 169 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this, |
| 154 check), | 170 check), |
| 155 download_urlcheck_timeout_ms_); | 171 download_url_check_timeout_); |
| 156 return false; | 172 return false; |
| 157 } | 173 } |
| 158 | 174 |
| 159 bool SafeBrowsingDatabaseManager::CheckDownloadHash( | 175 bool SafeBrowsingDatabaseManager::CheckDownloadHash( |
| 160 const std::string& full_hash, | 176 const std::string& full_hash, |
| 161 Client* client) { | 177 Client* client) { |
| 162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 163 DCHECK(!full_hash.empty()); | 179 DCHECK(!full_hash.empty()); |
| 164 if (!enabled_ || !enable_download_protection_ || full_hash.empty()) | 180 if (!enabled_ || !enable_download_protection_ || full_hash.empty()) |
| 165 return true; | 181 return true; |
| 166 | 182 |
| 167 // We need to check the database for url prefix, and later may fetch the url | 183 // 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. | 184 // from the safebrowsing backends. These need to be asynchronous. |
| 169 SafeBrowsingCheck* check = new SafeBrowsingCheck(); | 185 SafeBrowsingCheck* check = new SafeBrowsingCheck(safe_browsing_util::BINHASH); |
| 170 check->full_hash.reset(new SBFullHash); | 186 SBFullHash sb_hash; |
| 171 safe_browsing_util::StringToSBFullHash(full_hash, check->full_hash.get()); | 187 safe_browsing_util::StringToSBFullHash(full_hash, &sb_hash); |
| 172 StartDownloadCheck( | 188 check->full_hashes.push_back(sb_hash); |
| 189 StartSafeBrowsingCheck( |
| 173 check, | 190 check, |
| 174 client, | 191 client, |
| 175 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadHashOnSBThread,this, | 192 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadHashOnSBThread,this, |
| 176 check), | 193 check), |
| 177 download_hashcheck_timeout_ms_); | 194 download_hash_check_timeout_); |
| 178 return false; | 195 return false; |
| 179 } | 196 } |
| 180 | 197 |
| 181 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) { | 198 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) { |
| 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 183 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) { | 200 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) { |
| 184 // There is something funky going on here -- for example, perhaps the user | 201 // There is something funky going on here -- for example, perhaps the user |
| 185 // has not restarted since enabling metrics reporting, so we haven't | 202 // 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 | 203 // enabled the csd whitelist yet. Just to be safe we return true in this |
| 187 // case. | 204 // case. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 213 if (!enabled_) | 230 if (!enabled_) |
| 214 return true; | 231 return true; |
| 215 | 232 |
| 216 if (!CanCheckUrl(url)) | 233 if (!CanCheckUrl(url)) |
| 217 return true; | 234 return true; |
| 218 | 235 |
| 219 const base::TimeTicks start = base::TimeTicks::Now(); | 236 const base::TimeTicks start = base::TimeTicks::Now(); |
| 220 if (!MakeDatabaseAvailable()) { | 237 if (!MakeDatabaseAvailable()) { |
| 221 QueuedCheck check; | 238 QueuedCheck check; |
| 239 check.check_type = safe_browsing_util::MALWARE; // or PHISH |
| 222 check.client = client; | 240 check.client = client; |
| 223 check.url = url; | 241 check.url = url; |
| 224 check.start = start; | 242 check.start = start; |
| 225 queued_checks_.push_back(check); | 243 queued_checks_.push_back(check); |
| 226 return false; | 244 return false; |
| 227 } | 245 } |
| 228 | 246 |
| 229 std::string list; | 247 std::string list; |
| 230 std::vector<SBPrefix> prefix_hits; | 248 std::vector<SBPrefix> prefix_hits; |
| 231 std::vector<SBFullHashResult> full_hits; | 249 std::vector<SBFullHashResult> full_hits; |
| 232 | 250 |
| 233 bool prefix_match = | 251 bool prefix_match = |
| 234 database_->ContainsBrowseUrl(url, &list, &prefix_hits, &full_hits, | 252 database_->ContainsBrowseUrl(url, &list, &prefix_hits, &full_hits, |
| 235 sb_service_->protocol_manager()->last_update()); | 253 sb_service_->protocol_manager()->last_update()); |
| 236 | 254 |
| 237 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start); | 255 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start); |
| 238 | 256 |
| 239 if (!prefix_match) | 257 if (!prefix_match) |
| 240 return true; // URL is okay. | 258 return true; // URL is okay. |
| 241 | 259 |
| 242 // Needs to be asynchronous, since we could be in the constructor of a | 260 // Needs to be asynchronous, since we could be in the constructor of a |
| 243 // ResourceDispatcherHost event handler which can't pause there. | 261 // ResourceDispatcherHost event handler which can't pause there. |
| 244 SafeBrowsingCheck* check = new SafeBrowsingCheck(); | 262 SafeBrowsingCheck* check = |
| 263 new SafeBrowsingCheck(safe_browsing_util::MALWARE); // or PHISH |
| 245 check->urls.push_back(url); | 264 check->urls.push_back(url); |
| 246 check->client = client; | 265 check->client = client; |
| 247 check->threat_type = SB_THREAT_TYPE_SAFE; | |
| 248 check->is_download = false; | |
| 249 check->need_get_hash = full_hits.empty(); | 266 check->need_get_hash = full_hits.empty(); |
| 250 check->prefix_hits.swap(prefix_hits); | 267 check->prefix_hits.swap(prefix_hits); |
| 251 check->full_hits.swap(full_hits); | 268 check->full_hits.swap(full_hits); |
| 252 checks_.insert(check); | 269 checks_.insert(check); |
| 253 | 270 |
| 254 BrowserThread::PostTask( | 271 BrowserThread::PostTask( |
| 255 BrowserThread::IO, FROM_HERE, | 272 BrowserThread::IO, FROM_HERE, |
| 256 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); | 273 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); |
| 257 | 274 |
| 258 return false; | 275 return false; |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 if (!enabled_) | 411 if (!enabled_) |
| 395 return; | 412 return; |
| 396 | 413 |
| 397 enabled_ = false; | 414 enabled_ = false; |
| 398 | 415 |
| 399 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. | 416 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. |
| 400 // If we don't do this here we may fail to close the database below. | 417 // If we don't do this here we may fail to close the database below. |
| 401 while (!queued_checks_.empty()) { | 418 while (!queued_checks_.empty()) { |
| 402 QueuedCheck queued = queued_checks_.front(); | 419 QueuedCheck queued = queued_checks_.front(); |
| 403 if (queued.client) { | 420 if (queued.client) { |
| 404 SafeBrowsingCheck sb_check; | 421 SafeBrowsingCheck sb_check(queued.check_type); |
| 405 sb_check.urls.push_back(queued.url); | 422 sb_check.urls.push_back(queued.url); |
| 406 sb_check.client = queued.client; | 423 sb_check.client = queued.client; |
| 407 sb_check.threat_type = SB_THREAT_TYPE_SAFE; | |
| 408 queued.client->OnSafeBrowsingResult(sb_check); | 424 queued.client->OnSafeBrowsingResult(sb_check); |
| 409 } | 425 } |
| 410 queued_checks_.pop_front(); | 426 queued_checks_.pop_front(); |
| 411 } | 427 } |
| 412 | 428 |
| 413 // Close the database. We don't simply DeleteSoon() because if a close is | 429 // Close the database. We don't simply DeleteSoon() because if a close is |
| 414 // already pending, we'll double-free, and we don't set |database_| to NULL | 430 // already pending, we'll double-free, and we don't set |database_| to NULL |
| 415 // because if there is still anything running on the db thread, it could | 431 // because if there is still anything running on the db thread, it could |
| 416 // create a new database object (via GetDatabase()) that would then leak. | 432 // create a new database object (via GetDatabase()) that would then leak. |
| 417 CloseDatabase(); | 433 CloseDatabase(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 429 safe_browsing_thread_.reset(); | 445 safe_browsing_thread_.reset(); |
| 430 } | 446 } |
| 431 | 447 |
| 432 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. | 448 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. |
| 433 // We have to do this after the db thread returns because methods on it can | 449 // We have to do this after the db thread returns because methods on it can |
| 434 // have copies of these pointers, so deleting them might lead to accessing | 450 // have copies of these pointers, so deleting them might lead to accessing |
| 435 // garbage. | 451 // garbage. |
| 436 for (CurrentChecks::iterator it = checks_.begin(); | 452 for (CurrentChecks::iterator it = checks_.begin(); |
| 437 it != checks_.end(); ++it) { | 453 it != checks_.end(); ++it) { |
| 438 SafeBrowsingCheck* check = *it; | 454 SafeBrowsingCheck* check = *it; |
| 439 if (check->client) { | 455 if (check->client) |
| 440 check->threat_type = SB_THREAT_TYPE_SAFE; | |
| 441 check->client->OnSafeBrowsingResult(*check); | 456 check->client->OnSafeBrowsingResult(*check); |
| 442 } | |
| 443 } | 457 } |
| 444 STLDeleteElements(&checks_); | 458 STLDeleteElements(&checks_); |
| 445 | 459 |
| 446 gethash_requests_.clear(); | 460 gethash_requests_.clear(); |
| 447 } | 461 } |
| 448 | 462 |
| 449 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const { | 463 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const { |
| 450 base::AutoLock lock(database_lock_); | 464 base::AutoLock lock(database_lock_); |
| 451 return !closing_database_ && (database_ != NULL); | 465 return !closing_database_ && (database_ != NULL); |
| 452 } | 466 } |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 GetHashRequestors requestors; | 566 GetHashRequestors requestors; |
| 553 requestors.push_back(check); | 567 requestors.push_back(check); |
| 554 gethash_requests_[prefix] = requestors; | 568 gethash_requests_[prefix] = requestors; |
| 555 } | 569 } |
| 556 | 570 |
| 557 // Reset the start time so that we can measure the network time without the | 571 // Reset the start time so that we can measure the network time without the |
| 558 // database time. | 572 // database time. |
| 559 check->start = base::TimeTicks::Now(); | 573 check->start = base::TimeTicks::Now(); |
| 560 // Note: If |this| is deleted or stopped, the protocol_manager will | 574 // Note: If |this| is deleted or stopped, the protocol_manager will |
| 561 // be destroyed as well - hence it's OK to do unretained in this case. | 575 // be destroyed as well - hence it's OK to do unretained in this case. |
| 576 bool is_download = check->check_type == safe_browsing_util::BINURL || |
| 577 check->check_type == safe_browsing_util::BINHASH; |
| 562 sb_service_->protocol_manager()->GetFullHash( | 578 sb_service_->protocol_manager()->GetFullHash( |
| 563 check->prefix_hits, | 579 check->prefix_hits, |
| 564 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults, | 580 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults, |
| 565 base::Unretained(this), | 581 base::Unretained(this), |
| 566 check), | 582 check), |
| 567 check->is_download); | 583 is_download); |
| 568 } else { | 584 } else { |
| 569 // We may have cached results for previous GetHash queries. Since | 585 // We may have cached results for previous GetHash queries. Since |
| 570 // this data comes from cache, don't histogram hits. | 586 // this data comes from cache, don't histogram hits. |
| 571 HandleOneCheck(check, check->full_hits); | 587 HandleOneCheck(check, check->full_hits); |
| 572 } | 588 } |
| 573 } | 589 } |
| 574 | 590 |
| 575 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase( | 591 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase( |
| 576 GetChunksCallback callback) { | 592 GetChunksCallback callback) { |
| 577 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); | 593 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 620 // below will add the check back to the queue, and we'll infinite-loop. | 636 // below will add the check back to the queue, and we'll infinite-loop. |
| 621 DCHECK(DatabaseAvailable()); | 637 DCHECK(DatabaseAvailable()); |
| 622 while (!queued_checks_.empty()) { | 638 while (!queued_checks_.empty()) { |
| 623 QueuedCheck check = queued_checks_.front(); | 639 QueuedCheck check = queued_checks_.front(); |
| 624 DCHECK(!check.start.is_null()); | 640 DCHECK(!check.start.is_null()); |
| 625 HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start); | 641 HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start); |
| 626 // If CheckUrl() determines the URL is safe immediately, it doesn't call the | 642 // If CheckUrl() determines the URL is safe immediately, it doesn't call the |
| 627 // client's handler function (because normally it's being directly called by | 643 // client's handler function (because normally it's being directly called by |
| 628 // the client). Since we're not the client, we have to convey this result. | 644 // the client). Since we're not the client, we have to convey this result. |
| 629 if (check.client && CheckBrowseUrl(check.url, check.client)) { | 645 if (check.client && CheckBrowseUrl(check.url, check.client)) { |
| 630 SafeBrowsingCheck sb_check; | 646 SafeBrowsingCheck sb_check(check.check_type); |
| 631 sb_check.urls.push_back(check.url); | 647 sb_check.urls.push_back(check.url); |
| 632 sb_check.client = check.client; | 648 sb_check.client = check.client; |
| 633 sb_check.threat_type = SB_THREAT_TYPE_SAFE; | |
| 634 check.client->OnSafeBrowsingResult(sb_check); | 649 check.client->OnSafeBrowsingResult(sb_check); |
| 635 } | 650 } |
| 636 queued_checks_.pop_front(); | 651 queued_checks_.pop_front(); |
| 637 } | 652 } |
| 638 } | 653 } |
| 639 | 654 |
| 640 void SafeBrowsingDatabaseManager::HandleChunkForDatabase( | 655 void SafeBrowsingDatabaseManager::HandleChunkForDatabase( |
| 641 const std::string& list_name, SBChunkList* chunks) { | 656 const std::string& list_name, SBChunkList* chunks) { |
| 642 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); | 657 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); |
| 643 if (chunks) { | 658 if (chunks) { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 const std::vector<SBPrefix>& prefixes, | 741 const std::vector<SBPrefix>& prefixes, |
| 727 const std::vector<SBFullHashResult>& full_hashes) { | 742 const std::vector<SBFullHashResult>& full_hashes) { |
| 728 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); | 743 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); |
| 729 GetDatabase()->CacheHashResults(prefixes, full_hashes); | 744 GetDatabase()->CacheHashResults(prefixes, full_hashes); |
| 730 } | 745 } |
| 731 | 746 |
| 732 void SafeBrowsingDatabaseManager::OnHandleGetHashResults( | 747 void SafeBrowsingDatabaseManager::OnHandleGetHashResults( |
| 733 SafeBrowsingCheck* check, | 748 SafeBrowsingCheck* check, |
| 734 const std::vector<SBFullHashResult>& full_hashes) { | 749 const std::vector<SBFullHashResult>& full_hashes) { |
| 735 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 750 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 736 bool is_download = check->is_download; | 751 safe_browsing_util::ListType check_type = check->check_type; |
| 737 SBPrefix prefix = check->prefix_hits[0]; | 752 SBPrefix prefix = check->prefix_hits[0]; |
| 738 GetHashRequests::iterator it = gethash_requests_.find(prefix); | 753 GetHashRequests::iterator it = gethash_requests_.find(prefix); |
| 739 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) { | 754 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) { |
| 740 const bool hit = HandleOneCheck(check, full_hashes); | 755 const bool hit = HandleOneCheck(check, full_hashes); |
| 741 RecordGetHashCheckStatus(hit, is_download, full_hashes); | 756 RecordGetHashCheckStatus(hit, check_type, full_hashes); |
| 742 return; | 757 return; |
| 743 } | 758 } |
| 744 | 759 |
| 745 // Call back all interested parties, noting if any has a hit. | 760 // Call back all interested parties, noting if any has a hit. |
| 746 GetHashRequestors& requestors = it->second; | 761 GetHashRequestors& requestors = it->second; |
| 747 bool hit = false; | 762 bool hit = false; |
| 748 for (GetHashRequestors::iterator r = requestors.begin(); | 763 for (GetHashRequestors::iterator r = requestors.begin(); |
| 749 r != requestors.end(); ++r) { | 764 r != requestors.end(); ++r) { |
| 750 if (HandleOneCheck(*r, full_hashes)) | 765 if (HandleOneCheck(*r, full_hashes)) |
| 751 hit = true; | 766 hit = true; |
| 752 } | 767 } |
| 753 RecordGetHashCheckStatus(hit, is_download, full_hashes); | 768 RecordGetHashCheckStatus(hit, check_type, full_hashes); |
| 754 | 769 |
| 755 gethash_requests_.erase(it); | 770 gethash_requests_.erase(it); |
| 756 } | 771 } |
| 757 | 772 |
| 758 bool SafeBrowsingDatabaseManager::HandleOneCheck( | 773 bool SafeBrowsingDatabaseManager::HandleOneCheck( |
| 759 SafeBrowsingCheck* check, | 774 SafeBrowsingCheck* check, |
| 760 const std::vector<SBFullHashResult>& full_hashes) { | 775 const std::vector<SBFullHashResult>& full_hashes) { |
| 761 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 776 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 762 DCHECK(check); | 777 DCHECK(check); |
| 763 | 778 |
| 764 // Always calculate the index, for recording hits. | 779 for (std::vector<GURL>::iterator it = check->urls.begin(); |
| 765 int index = -1; | 780 it != check->urls.end(); ++it) { |
| 766 if (!check->urls.empty()) { | 781 int index = safe_browsing_util::GetUrlHashIndex(*it, full_hashes); |
| 767 for (size_t i = 0; i < check->urls.size(); ++i) { | 782 if (index != -1) { |
| 768 index = safe_browsing_util::GetUrlHashIndex(check->urls[i], full_hashes); | 783 check->url_threats[*it] = |
| 769 if (index != -1) | 784 GetThreatTypeFromListname(full_hashes[index].list_name); |
| 770 break; | |
| 771 } | 785 } |
| 772 } else { | |
| 773 index = safe_browsing_util::GetHashIndex(*(check->full_hash), full_hashes); | |
| 774 } | 786 } |
| 775 | 787 |
| 776 // |client| is NULL if the request was cancelled. | 788 for (std::vector<SBFullHash>::iterator it = check->full_hashes.begin(); |
| 777 if (check->client) { | 789 it != check->full_hashes.end(); ++it) { |
| 778 check->threat_type = SB_THREAT_TYPE_SAFE; | 790 int index = safe_browsing_util::GetHashIndex(*it, full_hashes); |
| 779 if (index != -1) { | 791 if (index != -1) { |
| 780 check->threat_type = GetThreatTypeFromListname( | 792 check->full_hash_threats[*it] = |
| 781 full_hashes[index].list_name); | 793 GetThreatTypeFromListname(full_hashes[index].list_name); |
| 782 } | 794 } |
| 783 } | 795 } |
| 796 |
| 784 SafeBrowsingCheckDone(check); | 797 SafeBrowsingCheckDone(check); |
| 785 return (index != -1); | 798 return check->url_threats.empty() && check->full_hash_threats.empty(); |
| 786 } | 799 } |
| 787 | 800 |
| 788 void SafeBrowsingDatabaseManager::CheckDownloadHashOnSBThread( | 801 void SafeBrowsingDatabaseManager::CheckDownloadHashOnSBThread( |
| 789 SafeBrowsingCheck* check) { | 802 SafeBrowsingCheck* check) { |
| 790 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); | 803 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); |
| 791 DCHECK(enable_download_protection_); | 804 DCHECK(enable_download_protection_); |
| 792 | 805 |
| 793 if (!database_->ContainsDownloadHashPrefix(check->full_hash->prefix)) { | 806 DCHECK_EQ(1u, check->full_hashes.size()); |
| 807 SBFullHash full_hash = check->full_hashes[0]; |
| 808 |
| 809 if (!database_->ContainsDownloadHashPrefix(full_hash.prefix)) { |
| 794 // Good, we don't have hash for this url prefix. | 810 // Good, we don't have hash for this url prefix. |
| 795 check->threat_type = SB_THREAT_TYPE_SAFE; | |
| 796 BrowserThread::PostTask( | 811 BrowserThread::PostTask( |
| 797 BrowserThread::IO, FROM_HERE, | 812 BrowserThread::IO, FROM_HERE, |
| 798 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadHashDone, this, | 813 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadHashDone, this, |
| 799 check)); | 814 check)); |
| 800 return; | 815 return; |
| 801 } | 816 } |
| 802 | 817 |
| 803 check->need_get_hash = true; | 818 check->need_get_hash = true; |
| 804 check->prefix_hits.push_back(check->full_hash->prefix); | 819 check->prefix_hits.push_back(full_hash.prefix); |
| 805 BrowserThread::PostTask( | 820 BrowserThread::PostTask( |
| 806 BrowserThread::IO, FROM_HERE, | 821 BrowserThread::IO, FROM_HERE, |
| 807 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); | 822 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); |
| 808 } | 823 } |
| 809 | 824 |
| 810 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread( | 825 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread( |
| 811 SafeBrowsingCheck* check) { | 826 SafeBrowsingCheck* check) { |
| 812 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); | 827 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); |
| 813 DCHECK(enable_download_protection_); | 828 DCHECK(enable_download_protection_); |
| 814 | 829 |
| 815 std::vector<SBPrefix> prefix_hits; | 830 std::vector<SBPrefix> prefix_hits; |
| 816 | 831 |
| 817 if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) { | 832 if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) { |
| 818 // Good, we don't have hash for this url prefix. | 833 // Good, we don't have hash for this url prefix. |
| 819 check->threat_type = SB_THREAT_TYPE_SAFE; | |
| 820 BrowserThread::PostTask( | 834 BrowserThread::PostTask( |
| 821 BrowserThread::IO, FROM_HERE, | 835 BrowserThread::IO, FROM_HERE, |
| 822 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this, | 836 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this, |
| 823 check)); | 837 check)); |
| 824 return; | 838 return; |
| 825 } | 839 } |
| 826 | 840 |
| 827 check->need_get_hash = true; | 841 check->need_get_hash = true; |
| 828 check->prefix_hits.clear(); | 842 check->prefix_hits.clear(); |
| 829 check->prefix_hits = prefix_hits; | 843 check->prefix_hits = prefix_hits; |
| 830 BrowserThread::PostTask( | 844 BrowserThread::PostTask( |
| 831 BrowserThread::IO, FROM_HERE, | 845 BrowserThread::IO, FROM_HERE, |
| 832 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); | 846 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); |
| 833 } | 847 } |
| 834 | 848 |
| 835 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) { | 849 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) { |
| 836 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 850 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 837 DCHECK(check); | 851 DCHECK(check); |
| 838 | 852 |
| 839 if (!enabled_) | 853 if (!enabled_) |
| 840 return; | 854 return; |
| 841 | 855 |
| 842 DCHECK(checks_.find(check) != checks_.end()); | 856 DCHECK(checks_.find(check) != checks_.end()); |
| 843 DCHECK_EQ(check->threat_type, SB_THREAT_TYPE_SAFE); | |
| 844 if (check->client) { | 857 if (check->client) { |
| 845 check->client->OnSafeBrowsingResult(*check); | 858 check->client->OnSafeBrowsingResult(*check); |
| 846 check->client = NULL; | 859 check->client = NULL; |
| 847 } | 860 } |
| 848 } | 861 } |
| 849 | 862 |
| 850 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone( | 863 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone( |
| 851 SafeBrowsingCheck* check) { | 864 SafeBrowsingCheck* check) { |
| 852 DCHECK(enable_download_protection_); | 865 DCHECK(enable_download_protection_); |
| 853 SafeBrowsingCheckDone(check); | 866 SafeBrowsingCheckDone(check); |
| 854 } | 867 } |
| 855 | 868 |
| 856 void SafeBrowsingDatabaseManager::CheckDownloadHashDone( | 869 void SafeBrowsingDatabaseManager::CheckDownloadHashDone( |
| 857 SafeBrowsingCheck* check) { | 870 SafeBrowsingCheck* check) { |
| 858 DCHECK(enable_download_protection_); | 871 DCHECK(enable_download_protection_); |
| 859 SafeBrowsingCheckDone(check); | 872 SafeBrowsingCheckDone(check); |
| 860 } | 873 } |
| 861 | 874 |
| 862 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone( | 875 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone( |
| 863 SafeBrowsingCheck* check) { | 876 SafeBrowsingCheck* check) { |
| 864 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 877 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 865 DCHECK(check); | 878 DCHECK(check); |
| 866 | 879 |
| 867 if (!enabled_) | 880 if (!enabled_) |
| 868 return; | 881 return; |
| 869 | 882 |
| 870 VLOG(1) << "SafeBrowsingCheckDone: " << check->threat_type; | 883 VLOG(1) << "SafeBrowsingCheckDone: " << |
| 884 check->url_threats.size() << " URL hits, " << |
| 885 check->full_hash_threats.size() << " hash hits"; |
| 871 DCHECK(checks_.find(check) != checks_.end()); | 886 DCHECK(checks_.find(check) != checks_.end()); |
| 872 if (check->client) | 887 if (check->client) |
| 873 check->client->OnSafeBrowsingResult(*check); | 888 check->client->OnSafeBrowsingResult(*check); |
| 874 checks_.erase(check); | 889 checks_.erase(check); |
| 875 delete check; | 890 delete check; |
| 876 } | 891 } |
| 877 | 892 |
| 878 void SafeBrowsingDatabaseManager::StartDownloadCheck(SafeBrowsingCheck* check, | 893 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck( |
| 879 Client* client, | 894 SafeBrowsingCheck* check, |
| 880 const base::Closure& task, | 895 Client* client, |
| 881 int64 timeout_ms) { | 896 const base::Closure& task, |
| 882 | 897 const base::TimeDelta& timeout) { |
| 883 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 898 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 884 check->client = client; | 899 check->client = client; |
| 885 check->threat_type = SB_THREAT_TYPE_SAFE; | |
| 886 check->is_download = true; | |
| 887 check->timeout_factory_.reset( | 900 check->timeout_factory_.reset( |
| 888 new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this)); | 901 new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this)); |
| 889 checks_.insert(check); | 902 checks_.insert(check); |
| 890 | 903 |
| 891 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task); | 904 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task); |
| 892 | 905 |
| 893 MessageLoop::current()->PostDelayedTask(FROM_HERE, | 906 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| 894 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback, | 907 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback, |
| 895 check->timeout_factory_->GetWeakPtr(), check), | 908 check->timeout_factory_->GetWeakPtr(), check), |
| 896 base::TimeDelta::FromMilliseconds(timeout_ms)); | 909 timeout); |
| 897 } | 910 } |
| OLD | NEW |