| 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,
|
|
|