Index: chrome/browser/safe_browsing/protocol_manager.cc |
diff --git a/chrome/browser/safe_browsing/protocol_manager.cc b/chrome/browser/safe_browsing/protocol_manager.cc |
index 8fcc06b8fffb045355393371289e258938b17af6..0d68a91c8a0b2331d221e5b306e7ba468cc778f2 100644 |
--- a/chrome/browser/safe_browsing/protocol_manager.cc |
+++ b/chrome/browser/safe_browsing/protocol_manager.cc |
@@ -242,14 +242,17 @@ void SafeBrowsingProtocolManager::GetFullHash( |
std::string SafeBrowsingProtocolManager::GetV4HashRequest( |
const std::vector<SBPrefix>& prefixes, |
+ const std::vector<PlatformType>& platforms, |
ThreatType threat_type) { |
// Build the request. Client info and client states are not added to the |
// request protocol buffer. Client info is passed as params in the url. |
FindFullHashesRequest req; |
ThreatInfo* info = req.mutable_threat_info(); |
info->add_threat_types(threat_type); |
- info->add_platform_types(CHROME_PLATFORM); |
info->add_threat_entry_types(URL_EXPRESSION); |
+ for (const PlatformType p : platforms) { |
+ info->add_platform_types(p); |
+ } |
for (const SBPrefix& prefix : prefixes) { |
std::string hash(reinterpret_cast<const char*>(&prefix), sizeof(SBPrefix)); |
info->add_threat_entries()->set_hash(hash); |
@@ -263,21 +266,79 @@ std::string SafeBrowsingProtocolManager::GetV4HashRequest( |
return req_base64; |
} |
+bool SafeBrowsingProtocolManager::ParseV4HashResponse( |
+ const std::string& data, |
+ std::vector<SBFullHashResult>* full_hashes, |
+ base::TimeDelta* negative_cache_duration) { |
+ FindFullHashesResponse response; |
+ |
+ if (!response.ParseFromString(data)) { |
+ // TODO(kcarattini): Add UMA. |
+ return false; |
+ } |
+ |
+ if (response.has_negative_cache_duration()) { |
+ // Seconds resolution is good enough so we ignore the nanos field. |
+ *negative_cache_duration = base::TimeDelta::FromSeconds( |
+ response.negative_cache_duration().seconds()); |
+ } |
+ |
+ // Loop over the threat matches and fill in full_hashes. |
+ for (const ThreatMatch& match : response.matches()) { |
+ // Make sure the platform and threat entry type match. |
+ if (!(match.has_threat_entry_type() && |
+ match.threat_entry_type() == URL_EXPRESSION && |
+ match.has_threat())) { |
+ continue; |
+ } |
+ |
+ // Fill in the full hash. |
+ SBFullHashResult result; |
+ result.hash = StringToSBFullHash(match.threat().hash()); |
+ |
+ if (match.has_cache_duration()) { |
+ // Seconds resolution is good enough so we ignore the nanos field. |
+ result.cache_duration = base::TimeDelta::FromSeconds( |
+ match.cache_duration().seconds()); |
+ } |
+ |
+ // Different threat types will handle the metadata differently. |
+ if (match.has_threat_type() && match.threat_type() == API_ABUSE && |
+ match.has_platform_type() && |
+ match.platform_type() == CHROME_PLATFORM && |
+ match.has_threat_entry_metadata()) { |
+ // For API Abuse, store a csv of the returned permissions. |
+ for (const ThreatEntryMetadata::MetadataEntry& m : |
+ match.threat_entry_metadata().entries()) { |
+ if (m.key() == "permission") { |
+ result.metadata += m.value() + ","; |
+ } |
+ } |
+ } else { |
+ // TODO(kcarattini): Add UMA for unexpected threat type match. |
+ return false; |
+ } |
+ |
+ full_hashes->push_back(result); |
+ } |
+ return true; |
+} |
+ |
void SafeBrowsingProtocolManager::GetV4FullHashes( |
const std::vector<SBPrefix>& prefixes, |
+ const std::vector<PlatformType>& platforms, |
ThreatType threat_type, |
FullHashCallback callback) { |
DCHECK(CalledOnValidThread()); |
// TODO(kcarattini): Implement backoff behavior. |
- std::string req_base64 = GetV4HashRequest(prefixes, threat_type); |
+ std::string req_base64 = GetV4HashRequest(prefixes, platforms, threat_type); |
GURL gethash_url = GetV4HashUrl(req_base64); |
net::URLFetcher* fetcher = |
net::URLFetcher::Create(url_fetcher_id_++, gethash_url, |
net::URLFetcher::GET, this) |
.release(); |
- // TODO(kcarattini): Implement a new response processor. |
v4_hash_requests_[fetcher] = FullHashDetails(callback, |
false /* is_download */); |
@@ -289,7 +350,8 @@ void SafeBrowsingProtocolManager::GetV4FullHashes( |
void SafeBrowsingProtocolManager::GetFullHashesWithApis( |
const std::vector<SBPrefix>& prefixes, |
FullHashCallback callback) { |
- GetV4FullHashes(prefixes, API_ABUSE, callback); |
+ std::vector<PlatformType> platform = {CHROME_PLATFORM}; |
+ GetV4FullHashes(prefixes, platform, API_ABUSE, callback); |
} |
void SafeBrowsingProtocolManager::GetNextUpdate() { |
@@ -316,6 +378,7 @@ void SafeBrowsingProtocolManager::OnURLFetchComplete( |
scoped_ptr<const net::URLFetcher> fetcher; |
HashRequests::iterator it = hash_requests_.find(source); |
+ HashRequests::iterator v4_it = v4_hash_requests_.find(source); |
int response_code = source->GetResponseCode(); |
net::URLRequestStatus status = source->GetStatus(); |
@@ -323,7 +386,6 @@ void SafeBrowsingProtocolManager::OnURLFetchComplete( |
// GetHash response. |
RecordHttpResponseOrErrorCode(kGetHashUmaResponseMetricName, status, |
response_code); |
- fetcher.reset(it->first); |
const FullHashDetails& details = it->second; |
std::vector<SBFullHashResult> full_hashes; |
base::TimeDelta cache_lifetime; |
@@ -366,6 +428,35 @@ void SafeBrowsingProtocolManager::OnURLFetchComplete( |
details.callback.Run(full_hashes, cache_lifetime); |
hash_requests_.erase(it); |
+ } else if (v4_it != v4_hash_requests_.end()) { |
+ // V4 FindFullHashes response. |
+ const FullHashDetails& details = v4_it->second; |
+ std::vector<SBFullHashResult> full_hashes; |
+ base::TimeDelta negative_cache_duration; |
+ if (status.is_success() && response_code == net::HTTP_OK) { |
+ // TODO(kcarattini): Add UMA reporting. |
+ // TODO(kcarattini): Implement backoff and minimum waiting duration |
+ // compliance. |
+ std::string data; |
+ source->GetResponseAsString(&data); |
+ if (!ParseV4HashResponse(data, &full_hashes, &negative_cache_duration)) { |
+ full_hashes.clear(); |
+ // TODO(kcarattini): Add UMA reporting. |
+ } |
+ } else { |
+ // TODO(kcarattini): Handle error by setting backoff interval. |
+ // TODO(kcarattini): Add UMA reporting. |
+ DVLOG(1) << "SafeBrowsing GetEncodedFullHashes request for: " << |
+ source->GetURL() << " failed with error: " << status.error() << |
+ " and response code: " << response_code; |
+ } |
+ |
+ // Invoke the callback with full_hashes, even if there was a parse error or |
+ // an error response code (in which case full_hashes will be empty). The |
+ // caller can't be blocked indefinitely. |
+ details.callback.Run(full_hashes, negative_cache_duration); |
+ |
+ v4_hash_requests_.erase(v4_it); |
} else { |
// Update or chunk response. |
RecordHttpResponseOrErrorCode(kGetChunkUmaResponseMetricName, status, |