| 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/download_protection_service.h" | 5 #include "chrome/browser/safe_browsing/download_protection_service.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 | 10 |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 | 272 |
| 273 class DownloadProtectionService::CheckClientDownloadRequest | 273 class DownloadProtectionService::CheckClientDownloadRequest |
| 274 : public base::RefCountedThreadSafe< | 274 : public base::RefCountedThreadSafe< |
| 275 DownloadProtectionService::CheckClientDownloadRequest, | 275 DownloadProtectionService::CheckClientDownloadRequest, |
| 276 BrowserThread::DeleteOnUIThread>, | 276 BrowserThread::DeleteOnUIThread>, |
| 277 public net::URLFetcherDelegate, | 277 public net::URLFetcherDelegate, |
| 278 public content::DownloadItem::Observer { | 278 public content::DownloadItem::Observer { |
| 279 public: | 279 public: |
| 280 CheckClientDownloadRequest( | 280 CheckClientDownloadRequest( |
| 281 content::DownloadItem* item, | 281 content::DownloadItem* item, |
| 282 const CheckDownloadCallback& callback, | 282 const CheckDownloadContentCallback& callback, |
| 283 DownloadProtectionService* service, | 283 DownloadProtectionService* service, |
| 284 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, | 284 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, |
| 285 BinaryFeatureExtractor* binary_feature_extractor) | 285 BinaryFeatureExtractor* binary_feature_extractor) |
| 286 : item_(item), | 286 : item_(item), |
| 287 url_chain_(item->GetUrlChain()), | 287 url_chain_(item->GetUrlChain()), |
| 288 referrer_url_(item->GetReferrerUrl()), | 288 referrer_url_(item->GetReferrerUrl()), |
| 289 tab_url_(item->GetTabUrl()), | 289 tab_url_(item->GetTabUrl()), |
| 290 tab_referrer_url_(item->GetTabReferrerUrl()), | 290 tab_referrer_url_(item->GetTabReferrerUrl()), |
| 291 archived_executable_(false), | 291 archived_executable_(false), |
| 292 archive_is_valid_(ArchiveValid::UNSET), | 292 archive_is_valid_(ArchiveValid::UNSET), |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 if (fetcher_.get()) { | 415 if (fetcher_.get()) { |
| 416 // The DownloadProtectionService is going to release its reference, so we | 416 // The DownloadProtectionService is going to release its reference, so we |
| 417 // might be destroyed before the URLFetcher completes. Cancel the | 417 // might be destroyed before the URLFetcher completes. Cancel the |
| 418 // fetcher so it does not try to invoke OnURLFetchComplete. | 418 // fetcher so it does not try to invoke OnURLFetchComplete. |
| 419 fetcher_.reset(); | 419 fetcher_.reset(); |
| 420 } | 420 } |
| 421 // Note: If there is no fetcher, then some callback is still holding a | 421 // Note: If there is no fetcher, then some callback is still holding a |
| 422 // reference to this object. We'll eventually wind up in some method on | 422 // reference to this object. We'll eventually wind up in some method on |
| 423 // the UI thread that will call FinishRequest() again. If FinishRequest() | 423 // the UI thread that will call FinishRequest() again. If FinishRequest() |
| 424 // is called a second time, it will be a no-op. | 424 // is called a second time, it will be a no-op. |
| 425 FinishRequest(UNKNOWN, REASON_REQUEST_CANCELED); | 425 FinishRequest(UNKNOWN, REASON_REQUEST_CANCELED, base::EmptyString()); |
| 426 // Calling FinishRequest might delete this object, we may be deleted by | 426 // Calling FinishRequest might delete this object, we may be deleted by |
| 427 // this point. | 427 // this point. |
| 428 } | 428 } |
| 429 | 429 |
| 430 // content::DownloadItem::Observer implementation. | 430 // content::DownloadItem::Observer implementation. |
| 431 void OnDownloadDestroyed(content::DownloadItem* download) override { | 431 void OnDownloadDestroyed(content::DownloadItem* download) override { |
| 432 Cancel(); | 432 Cancel(); |
| 433 DCHECK(item_ == NULL); | 433 DCHECK(item_ == NULL); |
| 434 } | 434 } |
| 435 | 435 |
| 436 // From the net::URLFetcherDelegate interface. | 436 // From the net::URLFetcherDelegate interface. |
| 437 void OnURLFetchComplete(const net::URLFetcher* source) override { | 437 void OnURLFetchComplete(const net::URLFetcher* source) override { |
| 438 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 438 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 439 DCHECK_EQ(source, fetcher_.get()); | 439 DCHECK_EQ(source, fetcher_.get()); |
| 440 DVLOG(2) << "Received a response for URL: " | 440 DVLOG(2) << "Received a response for URL: " |
| 441 << item_->GetUrlChain().back() << ": success=" | 441 << item_->GetUrlChain().back() << ": success=" |
| 442 << source->GetStatus().is_success() << " response_code=" | 442 << source->GetStatus().is_success() << " response_code=" |
| 443 << source->GetResponseCode(); | 443 << source->GetResponseCode(); |
| 444 if (source->GetStatus().is_success()) { | 444 if (source->GetStatus().is_success()) { |
| 445 UMA_HISTOGRAM_SPARSE_SLOWLY( | 445 UMA_HISTOGRAM_SPARSE_SLOWLY( |
| 446 "SBClientDownload.DownloadRequestResponseCode", | 446 "SBClientDownload.DownloadRequestResponseCode", |
| 447 source->GetResponseCode()); | 447 source->GetResponseCode()); |
| 448 } | 448 } |
| 449 UMA_HISTOGRAM_SPARSE_SLOWLY( | 449 UMA_HISTOGRAM_SPARSE_SLOWLY( |
| 450 "SBClientDownload.DownloadRequestNetError", | 450 "SBClientDownload.DownloadRequestNetError", |
| 451 -source->GetStatus().error()); | 451 -source->GetStatus().error()); |
| 452 DownloadCheckResultReason reason = REASON_SERVER_PING_FAILED; | 452 DownloadCheckResultReason reason = REASON_SERVER_PING_FAILED; |
| 453 DownloadCheckResult result = UNKNOWN; | 453 DownloadCheckResult result = UNKNOWN; |
| 454 std::string token; |
| 454 if (source->GetStatus().is_success() && | 455 if (source->GetStatus().is_success() && |
| 455 net::HTTP_OK == source->GetResponseCode()) { | 456 net::HTTP_OK == source->GetResponseCode()) { |
| 456 ClientDownloadResponse response; | 457 ClientDownloadResponse response; |
| 457 std::string data; | 458 std::string data; |
| 458 bool got_data = source->GetResponseAsString(&data); | 459 bool got_data = source->GetResponseAsString(&data); |
| 459 DCHECK(got_data); | 460 DCHECK(got_data); |
| 460 if (!response.ParseFromString(data)) { | 461 if (!response.ParseFromString(data)) { |
| 461 reason = REASON_INVALID_RESPONSE_PROTO; | 462 reason = REASON_INVALID_RESPONSE_PROTO; |
| 462 result = UNKNOWN; | 463 result = UNKNOWN; |
| 463 } else if (response.verdict() == ClientDownloadResponse::SAFE) { | 464 } else if (response.verdict() == ClientDownloadResponse::SAFE) { |
| 464 reason = REASON_DOWNLOAD_SAFE; | 465 reason = REASON_DOWNLOAD_SAFE; |
| 465 result = SAFE; | 466 result = SAFE; |
| 466 } else if (service_ && !service_->IsSupportedDownload( | 467 } else if (service_ && !service_->IsSupportedDownload( |
| 467 *item_, item_->GetTargetFilePath())) { | 468 *item_, item_->GetTargetFilePath())) { |
| 468 // The client of the download protection service assumes that we don't | 469 // The client of the download protection service assumes that we don't |
| 469 // support this download so we cannot return any other verdict than | 470 // support this download so we cannot return any other verdict than |
| 470 // UNKNOWN even if the server says it's dangerous to download this file. | 471 // UNKNOWN even if the server says it's dangerous to download this file. |
| 471 // Note: if service_ is NULL we already cancelled the request and | 472 // Note: if service_ is NULL we already cancelled the request and |
| 472 // returned UNKNOWN. | 473 // returned UNKNOWN. |
| 473 reason = REASON_DOWNLOAD_NOT_SUPPORTED; | 474 reason = REASON_DOWNLOAD_NOT_SUPPORTED; |
| 474 result = UNKNOWN; | 475 result = UNKNOWN; |
| 475 } else if (response.verdict() == ClientDownloadResponse::DANGEROUS) { | 476 } else if (response.verdict() == ClientDownloadResponse::DANGEROUS) { |
| 476 reason = REASON_DOWNLOAD_DANGEROUS; | 477 reason = REASON_DOWNLOAD_DANGEROUS; |
| 477 result = DANGEROUS; | 478 result = DANGEROUS; |
| 479 token = response.has_token() ? response.token() : base::EmptyString(); |
| 478 } else if (response.verdict() == ClientDownloadResponse::UNCOMMON) { | 480 } else if (response.verdict() == ClientDownloadResponse::UNCOMMON) { |
| 479 reason = REASON_DOWNLOAD_UNCOMMON; | 481 reason = REASON_DOWNLOAD_UNCOMMON; |
| 480 result = UNCOMMON; | 482 result = UNCOMMON; |
| 483 token = response.has_token() ? response.token() : base::EmptyString(); |
| 481 } else if (response.verdict() == ClientDownloadResponse::DANGEROUS_HOST) { | 484 } else if (response.verdict() == ClientDownloadResponse::DANGEROUS_HOST) { |
| 482 reason = REASON_DOWNLOAD_DANGEROUS_HOST; | 485 reason = REASON_DOWNLOAD_DANGEROUS_HOST; |
| 483 result = DANGEROUS_HOST; | 486 result = DANGEROUS_HOST; |
| 487 token = response.has_token() ? response.token() : base::EmptyString(); |
| 484 } else if ( | 488 } else if ( |
| 485 response.verdict() == ClientDownloadResponse::POTENTIALLY_UNWANTED) { | 489 response.verdict() == ClientDownloadResponse::POTENTIALLY_UNWANTED) { |
| 486 reason = REASON_DOWNLOAD_POTENTIALLY_UNWANTED; | 490 reason = REASON_DOWNLOAD_POTENTIALLY_UNWANTED; |
| 487 result = POTENTIALLY_UNWANTED; | 491 result = POTENTIALLY_UNWANTED; |
| 492 token = response.has_token() ? response.token() : base::EmptyString(); |
| 488 } else { | 493 } else { |
| 489 LOG(DFATAL) << "Unknown download response verdict: " | 494 LOG(DFATAL) << "Unknown download response verdict: " |
| 490 << response.verdict(); | 495 << response.verdict(); |
| 491 reason = REASON_INVALID_RESPONSE_VERDICT; | 496 reason = REASON_INVALID_RESPONSE_VERDICT; |
| 492 result = UNKNOWN; | 497 result = UNKNOWN; |
| 493 } | 498 } |
| 494 DownloadFeedbackService::MaybeStorePingsForDownload( | 499 DownloadFeedbackService::MaybeStorePingsForDownload( |
| 495 result, item_, client_download_request_data_, data); | 500 result, item_, client_download_request_data_, data); |
| 496 } | 501 } |
| 497 // We don't need the fetcher anymore. | 502 // We don't need the fetcher anymore. |
| 498 fetcher_.reset(); | 503 fetcher_.reset(); |
| 499 UMA_HISTOGRAM_TIMES("SBClientDownload.DownloadRequestDuration", | 504 UMA_HISTOGRAM_TIMES("SBClientDownload.DownloadRequestDuration", |
| 500 base::TimeTicks::Now() - start_time_); | 505 base::TimeTicks::Now() - start_time_); |
| 501 UMA_HISTOGRAM_TIMES("SBClientDownload.DownloadRequestNetworkDuration", | 506 UMA_HISTOGRAM_TIMES("SBClientDownload.DownloadRequestNetworkDuration", |
| 502 base::TimeTicks::Now() - request_start_time_); | 507 base::TimeTicks::Now() - request_start_time_); |
| 503 | 508 |
| 504 FinishRequest(result, reason); | 509 FinishRequest(result, reason, token); |
| 505 } | 510 } |
| 506 | 511 |
| 507 static bool IsSupportedDownload(const content::DownloadItem& item, | 512 static bool IsSupportedDownload(const content::DownloadItem& item, |
| 508 const base::FilePath& target_path, | 513 const base::FilePath& target_path, |
| 509 DownloadCheckResultReason* reason, | 514 DownloadCheckResultReason* reason, |
| 510 ClientDownloadRequest::DownloadType* type) { | 515 ClientDownloadRequest::DownloadType* type) { |
| 511 if (item.GetUrlChain().empty()) { | 516 if (item.GetUrlChain().empty()) { |
| 512 *reason = REASON_EMPTY_URL_CHAIN; | 517 *reason = REASON_EMPTY_URL_CHAIN; |
| 513 return false; | 518 return false; |
| 514 } | 519 } |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 931 item_->GetTargetFilePath().BaseName().AsUTF8Unsafe()); | 936 item_->GetTargetFilePath().BaseName().AsUTF8Unsafe()); |
| 932 request.set_download_type(type_); | 937 request.set_download_type(type_); |
| 933 if (archive_is_valid_ != ArchiveValid::UNSET) | 938 if (archive_is_valid_ != ArchiveValid::UNSET) |
| 934 request.set_archive_valid(archive_is_valid_ == ArchiveValid::VALID); | 939 request.set_archive_valid(archive_is_valid_ == ArchiveValid::VALID); |
| 935 request.mutable_signature()->CopyFrom(signature_info_); | 940 request.mutable_signature()->CopyFrom(signature_info_); |
| 936 if (image_headers_) | 941 if (image_headers_) |
| 937 request.set_allocated_image_headers(image_headers_.release()); | 942 request.set_allocated_image_headers(image_headers_.release()); |
| 938 if (archived_executable_) | 943 if (archived_executable_) |
| 939 request.mutable_archived_binary()->Swap(&archived_binary_); | 944 request.mutable_archived_binary()->Swap(&archived_binary_); |
| 940 if (!request.SerializeToString(&client_download_request_data_)) { | 945 if (!request.SerializeToString(&client_download_request_data_)) { |
| 941 FinishRequest(UNKNOWN, REASON_INVALID_REQUEST_PROTO); | 946 FinishRequest(UNKNOWN, REASON_INVALID_REQUEST_PROTO, base::EmptyString()); |
| 942 return; | 947 return; |
| 943 } | 948 } |
| 944 | 949 |
| 945 // User can manually blacklist a sha256 via flag, for testing. | 950 // User can manually blacklist a sha256 via flag, for testing. |
| 946 // This is checked just before the request is sent, to verify the request | 951 // This is checked just before the request is sent, to verify the request |
| 947 // would have been sent. This emmulates the server returning a DANGEROUS | 952 // would have been sent. This emmulates the server returning a DANGEROUS |
| 948 // verdict as closely as possible. | 953 // verdict as closely as possible. |
| 949 if (IsDownloadManuallyBlacklisted(request)) { | 954 if (IsDownloadManuallyBlacklisted(request)) { |
| 950 DVLOG(1) << "Download verdict overridden to DANGEROUS by flag."; | 955 DVLOG(1) << "Download verdict overridden to DANGEROUS by flag."; |
| 951 PostFinishTask(DANGEROUS, REASON_MANUAL_BLACKLIST); | 956 PostFinishTask(DANGEROUS, REASON_MANUAL_BLACKLIST); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 970 client_download_request_data_.size()); | 975 client_download_request_data_.size()); |
| 971 fetcher_->Start(); | 976 fetcher_->Start(); |
| 972 } | 977 } |
| 973 | 978 |
| 974 void PostFinishTask(DownloadCheckResult result, | 979 void PostFinishTask(DownloadCheckResult result, |
| 975 DownloadCheckResultReason reason) { | 980 DownloadCheckResultReason reason) { |
| 976 BrowserThread::PostTask( | 981 BrowserThread::PostTask( |
| 977 BrowserThread::UI, | 982 BrowserThread::UI, |
| 978 FROM_HERE, | 983 FROM_HERE, |
| 979 base::Bind(&CheckClientDownloadRequest::FinishRequest, this, result, | 984 base::Bind(&CheckClientDownloadRequest::FinishRequest, this, result, |
| 980 reason)); | 985 reason, base::EmptyString())); |
| 981 } | 986 } |
| 982 | 987 |
| 983 void FinishRequest(DownloadCheckResult result, | 988 void FinishRequest(DownloadCheckResult result, |
| 984 DownloadCheckResultReason reason) { | 989 DownloadCheckResultReason reason, |
| 990 const std::string& token) { |
| 985 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 991 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 986 if (finished_) { | 992 if (finished_) { |
| 987 return; | 993 return; |
| 988 } | 994 } |
| 989 finished_ = true; | 995 finished_ = true; |
| 990 | 996 |
| 991 // Ensure the timeout task is cancelled while we still have a non-zero | 997 // Ensure the timeout task is cancelled while we still have a non-zero |
| 992 // refcount. (crbug.com/240449) | 998 // refcount. (crbug.com/240449) |
| 993 weakptr_factory_.InvalidateWeakPtrs(); | 999 weakptr_factory_.InvalidateWeakPtrs(); |
| 994 if (!request_start_time_.is_null()) { | 1000 if (!request_start_time_.is_null()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1005 base::TimeTicks::Now() - timeout_start_time_); | 1011 base::TimeTicks::Now() - timeout_start_time_); |
| 1006 } | 1012 } |
| 1007 } | 1013 } |
| 1008 if (service_) { | 1014 if (service_) { |
| 1009 DVLOG(2) << "SafeBrowsing download verdict for: " | 1015 DVLOG(2) << "SafeBrowsing download verdict for: " |
| 1010 << item_->DebugString(true) << " verdict:" << reason | 1016 << item_->DebugString(true) << " verdict:" << reason |
| 1011 << " result:" << result; | 1017 << " result:" << result; |
| 1012 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", | 1018 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", |
| 1013 reason, | 1019 reason, |
| 1014 REASON_MAX); | 1020 REASON_MAX); |
| 1015 callback_.Run(result); | 1021 callback_.Run(result, token); |
| 1016 item_->RemoveObserver(this); | 1022 item_->RemoveObserver(this); |
| 1017 item_ = NULL; | 1023 item_ = NULL; |
| 1018 DownloadProtectionService* service = service_; | 1024 DownloadProtectionService* service = service_; |
| 1019 service_ = NULL; | 1025 service_ = NULL; |
| 1020 service->RequestFinished(this); | 1026 service->RequestFinished(this); |
| 1021 // DownloadProtectionService::RequestFinished will decrement our refcount, | 1027 // DownloadProtectionService::RequestFinished will decrement our refcount, |
| 1022 // so we may be deleted now. | 1028 // so we may be deleted now. |
| 1023 } else { | 1029 } else { |
| 1024 callback_.Run(UNKNOWN); | 1030 callback_.Run(UNKNOWN, base::EmptyString()); |
| 1025 } | 1031 } |
| 1026 } | 1032 } |
| 1027 | 1033 |
| 1028 bool CertificateChainIsWhitelisted( | 1034 bool CertificateChainIsWhitelisted( |
| 1029 const ClientDownloadRequest_CertificateChain& chain) { | 1035 const ClientDownloadRequest_CertificateChain& chain) { |
| 1030 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1036 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1031 if (chain.element_size() < 2) { | 1037 if (chain.element_size() < 2) { |
| 1032 // We need to have both a signing certificate and its issuer certificate | 1038 // We need to have both a signing certificate and its issuer certificate |
| 1033 // present to construct a whitelist entry. | 1039 // present to construct a whitelist entry. |
| 1034 return false; | 1040 return false; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1080 GURL tab_url_; | 1086 GURL tab_url_; |
| 1081 GURL tab_referrer_url_; | 1087 GURL tab_referrer_url_; |
| 1082 | 1088 |
| 1083 bool archived_executable_; | 1089 bool archived_executable_; |
| 1084 ArchiveValid archive_is_valid_; | 1090 ArchiveValid archive_is_valid_; |
| 1085 | 1091 |
| 1086 ClientDownloadRequest_SignatureInfo signature_info_; | 1092 ClientDownloadRequest_SignatureInfo signature_info_; |
| 1087 std::unique_ptr<ClientDownloadRequest_ImageHeaders> image_headers_; | 1093 std::unique_ptr<ClientDownloadRequest_ImageHeaders> image_headers_; |
| 1088 google::protobuf::RepeatedPtrField<ClientDownloadRequest_ArchivedBinary> | 1094 google::protobuf::RepeatedPtrField<ClientDownloadRequest_ArchivedBinary> |
| 1089 archived_binary_; | 1095 archived_binary_; |
| 1090 CheckDownloadCallback callback_; | 1096 CheckDownloadContentCallback callback_; |
| 1091 // Will be NULL if the request has been canceled. | 1097 // Will be NULL if the request has been canceled. |
| 1092 DownloadProtectionService* service_; | 1098 DownloadProtectionService* service_; |
| 1093 scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor_; | 1099 scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor_; |
| 1094 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; | 1100 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; |
| 1095 const bool pingback_enabled_; | 1101 const bool pingback_enabled_; |
| 1096 std::unique_ptr<net::URLFetcher> fetcher_; | 1102 std::unique_ptr<net::URLFetcher> fetcher_; |
| 1097 scoped_refptr<SandboxedZipAnalyzer> analyzer_; | 1103 scoped_refptr<SandboxedZipAnalyzer> analyzer_; |
| 1098 base::TimeTicks zip_analysis_start_time_; | 1104 base::TimeTicks zip_analysis_start_time_; |
| 1099 #if defined(OS_MACOSX) | 1105 #if defined(OS_MACOSX) |
| 1100 scoped_refptr<SandboxedDMGAnalyzer> dmg_analyzer_; | 1106 scoped_refptr<SandboxedDMGAnalyzer> dmg_analyzer_; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1143 REQUEST_MALFORMED, | 1149 REQUEST_MALFORMED, |
| 1144 FETCH_FAILED, | 1150 FETCH_FAILED, |
| 1145 RESPONSE_MALFORMED, | 1151 RESPONSE_MALFORMED, |
| 1146 SUCCEEDED | 1152 SUCCEEDED |
| 1147 }; | 1153 }; |
| 1148 | 1154 |
| 1149 PPAPIDownloadRequest( | 1155 PPAPIDownloadRequest( |
| 1150 const GURL& requestor_url, | 1156 const GURL& requestor_url, |
| 1151 const base::FilePath& default_file_path, | 1157 const base::FilePath& default_file_path, |
| 1152 const std::vector<base::FilePath::StringType>& alternate_extensions, | 1158 const std::vector<base::FilePath::StringType>& alternate_extensions, |
| 1153 const CheckDownloadCallback& callback, | 1159 const CheckDownloadContentCallback& callback, |
| 1154 DownloadProtectionService* service, | 1160 DownloadProtectionService* service, |
| 1155 scoped_refptr<SafeBrowsingDatabaseManager> database_manager) | 1161 scoped_refptr<SafeBrowsingDatabaseManager> database_manager) |
| 1156 : requestor_url_(requestor_url), | 1162 : requestor_url_(requestor_url), |
| 1157 default_file_path_(default_file_path), | 1163 default_file_path_(default_file_path), |
| 1158 alternate_extensions_(alternate_extensions), | 1164 alternate_extensions_(alternate_extensions), |
| 1159 callback_(callback), | 1165 callback_(callback), |
| 1160 service_(service), | 1166 service_(service), |
| 1161 database_manager_(database_manager), | 1167 database_manager_(database_manager), |
| 1162 start_time_(base::TimeTicks::Now()), | 1168 start_time_(base::TimeTicks::Now()), |
| 1163 supported_path_( | 1169 supported_path_( |
| 1164 GetSupportedFilePath(default_file_path, alternate_extensions)), | 1170 GetSupportedFilePath(default_file_path, alternate_extensions)), |
| 1165 weakptr_factory_(this) {} | 1171 weakptr_factory_(this) {} |
| 1166 | 1172 |
| 1167 ~PPAPIDownloadRequest() override { | 1173 ~PPAPIDownloadRequest() override { |
| 1168 if (fetcher_ && !callback_.is_null()) | 1174 if (fetcher_ && !callback_.is_null()) |
| 1169 Finish(RequestOutcome::REQUEST_DESTROYED, UNKNOWN); | 1175 Finish(RequestOutcome::REQUEST_DESTROYED, UNKNOWN, base::EmptyString()); |
| 1170 } | 1176 } |
| 1171 | 1177 |
| 1172 // Start the process of checking the download request. The callback passed as | 1178 // Start the process of checking the download request. The callback passed as |
| 1173 // the |callback| parameter to the constructor will be invoked with the result | 1179 // the |callback| parameter to the constructor will be invoked with the result |
| 1174 // of the check at some point in the future. | 1180 // of the check at some point in the future. |
| 1175 // | 1181 // |
| 1176 // From the this point on, the code is arranged to follow the most common | 1182 // From the this point on, the code is arranged to follow the most common |
| 1177 // workflow. | 1183 // workflow. |
| 1178 // | 1184 // |
| 1179 // Note that |this| should be added to the list of pending requests in the | 1185 // Note that |this| should be added to the list of pending requests in the |
| 1180 // associated DownloadProtectionService object *before* calling Start(). | 1186 // associated DownloadProtectionService object *before* calling Start(). |
| 1181 // Otherwise a synchronous Finish() call may result in leaking the | 1187 // Otherwise a synchronous Finish() call may result in leaking the |
| 1182 // PPAPIDownloadRequest object. This is enforced via a DCHECK in | 1188 // PPAPIDownloadRequest object. This is enforced via a DCHECK in |
| 1183 // DownloadProtectionService. | 1189 // DownloadProtectionService. |
| 1184 void Start() { | 1190 void Start() { |
| 1185 DVLOG(2) << "Starting SafeBrowsing download check for PPAPI download from " | 1191 DVLOG(2) << "Starting SafeBrowsing download check for PPAPI download from " |
| 1186 << requestor_url_ << " for [" << default_file_path_.value() << "] " | 1192 << requestor_url_ << " for [" << default_file_path_.value() << "] " |
| 1187 << "supported path is [" << supported_path_.value() << "]"; | 1193 << "supported path is [" << supported_path_.value() << "]"; |
| 1188 | 1194 |
| 1189 if (supported_path_.empty()) { | 1195 if (supported_path_.empty()) { |
| 1190 // Neither the default_file_path_ nor any path resulting of trying out | 1196 // Neither the default_file_path_ nor any path resulting of trying out |
| 1191 // |alternate_extensions_| are supported by SafeBrowsing. | 1197 // |alternate_extensions_| are supported by SafeBrowsing. |
| 1192 Finish(RequestOutcome::UNSUPPORTED_FILE_TYPE, SAFE); | 1198 Finish(RequestOutcome::UNSUPPORTED_FILE_TYPE, SAFE, base::EmptyString()); |
| 1193 return; | 1199 return; |
| 1194 } | 1200 } |
| 1195 | 1201 |
| 1196 // In case the request take too long, the check will abort with an UNKNOWN | 1202 // In case the request take too long, the check will abort with an UNKNOWN |
| 1197 // verdict. The weak pointer used for the timeout will be invalidated (and | 1203 // verdict. The weak pointer used for the timeout will be invalidated (and |
| 1198 // hence would prevent the timeout) if the check completes on time and | 1204 // hence would prevent the timeout) if the check completes on time and |
| 1199 // execution reaches Finish(). | 1205 // execution reaches Finish(). |
| 1200 BrowserThread::PostDelayedTask( | 1206 BrowserThread::PostDelayedTask( |
| 1201 BrowserThread::UI, FROM_HERE, | 1207 BrowserThread::UI, FROM_HERE, |
| 1202 base::Bind(&PPAPIDownloadRequest::OnRequestTimedOut, | 1208 base::Bind(&PPAPIDownloadRequest::OnRequestTimedOut, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1227 BrowserThread::UI, FROM_HERE, | 1233 BrowserThread::UI, FROM_HERE, |
| 1228 base::Bind(&PPAPIDownloadRequest::WhitelistCheckComplete, | 1234 base::Bind(&PPAPIDownloadRequest::WhitelistCheckComplete, |
| 1229 download_request, url_was_whitelisted)); | 1235 download_request, url_was_whitelisted)); |
| 1230 } | 1236 } |
| 1231 | 1237 |
| 1232 void WhitelistCheckComplete(bool was_on_whitelist) { | 1238 void WhitelistCheckComplete(bool was_on_whitelist) { |
| 1233 DVLOG(2) << __FUNCTION__ << " was_on_whitelist:" << was_on_whitelist; | 1239 DVLOG(2) << __FUNCTION__ << " was_on_whitelist:" << was_on_whitelist; |
| 1234 if (was_on_whitelist) { | 1240 if (was_on_whitelist) { |
| 1235 // TODO(asanka): Should sample whitelisted downloads based on | 1241 // TODO(asanka): Should sample whitelisted downloads based on |
| 1236 // service_->whitelist_sample_rate(). http://crbug.com/610924 | 1242 // service_->whitelist_sample_rate(). http://crbug.com/610924 |
| 1237 Finish(RequestOutcome::WHITELIST_HIT, SAFE); | 1243 Finish(RequestOutcome::WHITELIST_HIT, SAFE, base::EmptyString()); |
| 1238 return; | 1244 return; |
| 1239 } | 1245 } |
| 1240 | 1246 |
| 1241 // Not on whitelist, so we are going to check with the SafeBrowsing | 1247 // Not on whitelist, so we are going to check with the SafeBrowsing |
| 1242 // backend. | 1248 // backend. |
| 1243 SendRequest(); | 1249 SendRequest(); |
| 1244 } | 1250 } |
| 1245 | 1251 |
| 1246 void SendRequest() { | 1252 void SendRequest() { |
| 1247 DVLOG(2) << __FUNCTION__; | 1253 DVLOG(2) << __FUNCTION__; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1264 base::FilePath(alternate_extension).AsUTF8Unsafe(); | 1270 base::FilePath(alternate_extension).AsUTF8Unsafe(); |
| 1265 } | 1271 } |
| 1266 if (supported_path_ != default_file_path_) { | 1272 if (supported_path_ != default_file_path_) { |
| 1267 *(request.add_alternate_extensions()) = | 1273 *(request.add_alternate_extensions()) = |
| 1268 base::FilePath(default_file_path_.FinalExtension()).AsUTF8Unsafe(); | 1274 base::FilePath(default_file_path_.FinalExtension()).AsUTF8Unsafe(); |
| 1269 } | 1275 } |
| 1270 | 1276 |
| 1271 if (!request.SerializeToString(&client_download_request_data_)) { | 1277 if (!request.SerializeToString(&client_download_request_data_)) { |
| 1272 // More of an internal error than anything else. Note that the UNKNOWN | 1278 // More of an internal error than anything else. Note that the UNKNOWN |
| 1273 // verdict gets interpreted as "allowed". | 1279 // verdict gets interpreted as "allowed". |
| 1274 Finish(RequestOutcome::REQUEST_MALFORMED, UNKNOWN); | 1280 Finish(RequestOutcome::REQUEST_MALFORMED, UNKNOWN, base::EmptyString()); |
| 1275 return; | 1281 return; |
| 1276 } | 1282 } |
| 1277 | 1283 |
| 1278 fetcher_ = net::URLFetcher::Create(0, GetDownloadRequestUrl(), | 1284 fetcher_ = net::URLFetcher::Create(0, GetDownloadRequestUrl(), |
| 1279 net::URLFetcher::POST, this); | 1285 net::URLFetcher::POST, this); |
| 1280 fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE); | 1286 fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE); |
| 1281 fetcher_->SetAutomaticallyRetryOn5xx(false); | 1287 fetcher_->SetAutomaticallyRetryOn5xx(false); |
| 1282 fetcher_->SetRequestContext(service_->request_context_getter_.get()); | 1288 fetcher_->SetRequestContext(service_->request_context_getter_.get()); |
| 1283 fetcher_->SetUploadData("application/octet-stream", | 1289 fetcher_->SetUploadData("application/octet-stream", |
| 1284 client_download_request_data_); | 1290 client_download_request_data_); |
| 1285 fetcher_->Start(); | 1291 fetcher_->Start(); |
| 1286 } | 1292 } |
| 1287 | 1293 |
| 1288 // net::URLFetcherDelegate | 1294 // net::URLFetcherDelegate |
| 1289 void OnURLFetchComplete(const net::URLFetcher* source) override { | 1295 void OnURLFetchComplete(const net::URLFetcher* source) override { |
| 1290 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1296 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 1291 | 1297 |
| 1292 if (!source->GetStatus().is_success() || | 1298 if (!source->GetStatus().is_success() || |
| 1293 net::HTTP_OK != source->GetResponseCode()) { | 1299 net::HTTP_OK != source->GetResponseCode()) { |
| 1294 Finish(RequestOutcome::FETCH_FAILED, UNKNOWN); | 1300 Finish(RequestOutcome::FETCH_FAILED, UNKNOWN, base::EmptyString()); |
| 1295 return; | 1301 return; |
| 1296 } | 1302 } |
| 1297 | 1303 |
| 1298 ClientDownloadResponse response; | 1304 ClientDownloadResponse response; |
| 1299 std::string response_body; | 1305 std::string response_body; |
| 1306 std::string token; |
| 1300 bool got_data = source->GetResponseAsString(&response_body); | 1307 bool got_data = source->GetResponseAsString(&response_body); |
| 1301 DCHECK(got_data); | 1308 DCHECK(got_data); |
| 1302 | 1309 |
| 1303 if (response.ParseFromString(response_body)) { | 1310 if (response.ParseFromString(response_body)) { |
| 1311 token = response.has_token() ? response.token() : base::EmptyString(); |
| 1304 Finish(RequestOutcome::SUCCEEDED, | 1312 Finish(RequestOutcome::SUCCEEDED, |
| 1305 DownloadCheckResultFromClientDownloadResponse(response.verdict())); | 1313 DownloadCheckResultFromClientDownloadResponse(response.verdict()), |
| 1314 token); |
| 1306 } else { | 1315 } else { |
| 1307 Finish(RequestOutcome::RESPONSE_MALFORMED, UNKNOWN); | 1316 Finish(RequestOutcome::RESPONSE_MALFORMED, UNKNOWN, base::EmptyString()); |
| 1308 } | 1317 } |
| 1309 } | 1318 } |
| 1310 | 1319 |
| 1311 void OnRequestTimedOut() { | 1320 void OnRequestTimedOut() { |
| 1312 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1321 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 1313 DVLOG(2) << __FUNCTION__; | 1322 DVLOG(2) << __FUNCTION__; |
| 1314 Finish(RequestOutcome::TIMEDOUT, UNKNOWN); | 1323 Finish(RequestOutcome::TIMEDOUT, UNKNOWN, base::EmptyString()); |
| 1315 } | 1324 } |
| 1316 | 1325 |
| 1317 void Finish(RequestOutcome reason, DownloadCheckResult response) { | 1326 void Finish(RequestOutcome reason, |
| 1327 DownloadCheckResult response, |
| 1328 const std::string& token) { |
| 1318 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1329 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 1319 DVLOG(2) << __FUNCTION__ << " response: " << response; | 1330 DVLOG(2) << __FUNCTION__ << " response: " << response; |
| 1320 UMA_HISTOGRAM_SPARSE_SLOWLY( | 1331 UMA_HISTOGRAM_SPARSE_SLOWLY( |
| 1321 "SBClientDownload.PPAPIDownloadRequest.RequestOutcome", | 1332 "SBClientDownload.PPAPIDownloadRequest.RequestOutcome", |
| 1322 static_cast<int>(reason)); | 1333 static_cast<int>(reason)); |
| 1323 UMA_HISTOGRAM_SPARSE_SLOWLY("SBClientDownload.PPAPIDownloadRequest.Result", | 1334 UMA_HISTOGRAM_SPARSE_SLOWLY("SBClientDownload.PPAPIDownloadRequest.Result", |
| 1324 response); | 1335 response); |
| 1325 UMA_HISTOGRAM_TIMES("SBClientDownload.PPAPIDownloadRequest.RequestDuration", | 1336 UMA_HISTOGRAM_TIMES("SBClientDownload.PPAPIDownloadRequest.RequestDuration", |
| 1326 start_time_ - base::TimeTicks::Now()); | 1337 start_time_ - base::TimeTicks::Now()); |
| 1327 if (!callback_.is_null()) | 1338 if (!callback_.is_null()) |
| 1328 base::ResetAndReturn(&callback_).Run(response); | 1339 base::ResetAndReturn(&callback_).Run(response, token); |
| 1329 fetcher_.reset(); | 1340 fetcher_.reset(); |
| 1330 weakptr_factory_.InvalidateWeakPtrs(); | 1341 weakptr_factory_.InvalidateWeakPtrs(); |
| 1331 service_->PPAPIDownloadCheckRequestFinished(this); | 1342 service_->PPAPIDownloadCheckRequestFinished(this); |
| 1332 // |this| is deleted. | 1343 // |this| is deleted. |
| 1333 } | 1344 } |
| 1334 | 1345 |
| 1335 static DownloadCheckResult DownloadCheckResultFromClientDownloadResponse( | 1346 static DownloadCheckResult DownloadCheckResultFromClientDownloadResponse( |
| 1336 ClientDownloadResponse::Verdict verdict) { | 1347 ClientDownloadResponse::Verdict verdict) { |
| 1337 switch (verdict) { | 1348 switch (verdict) { |
| 1338 case ClientDownloadResponse::SAFE: | 1349 case ClientDownloadResponse::SAFE: |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1378 const GURL requestor_url_; | 1389 const GURL requestor_url_; |
| 1379 | 1390 |
| 1380 // Default download path requested by the PPAPI plugin. | 1391 // Default download path requested by the PPAPI plugin. |
| 1381 const base::FilePath default_file_path_; | 1392 const base::FilePath default_file_path_; |
| 1382 | 1393 |
| 1383 // List of alternate extensions provided by the PPAPI plugin. Each extension | 1394 // List of alternate extensions provided by the PPAPI plugin. Each extension |
| 1384 // must begin with a leading extension separator. | 1395 // must begin with a leading extension separator. |
| 1385 const std::vector<base::FilePath::StringType> alternate_extensions_; | 1396 const std::vector<base::FilePath::StringType> alternate_extensions_; |
| 1386 | 1397 |
| 1387 // Callback to invoke with the result of the PPAPI download request check. | 1398 // Callback to invoke with the result of the PPAPI download request check. |
| 1388 CheckDownloadCallback callback_; | 1399 CheckDownloadContentCallback callback_; |
| 1389 | 1400 |
| 1390 DownloadProtectionService* service_; | 1401 DownloadProtectionService* service_; |
| 1391 const scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; | 1402 const scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; |
| 1392 | 1403 |
| 1393 // Time request was started. | 1404 // Time request was started. |
| 1394 const base::TimeTicks start_time_; | 1405 const base::TimeTicks start_time_; |
| 1395 | 1406 |
| 1396 // A download path that is supported by SafeBrowsing. This is determined by | 1407 // A download path that is supported by SafeBrowsing. This is determined by |
| 1397 // invoking GetSupportedFilePath(). If non-empty, | 1408 // invoking GetSupportedFilePath(). If non-empty, |
| 1398 // safe_browsing::IsSupportedBinaryFile(supported_path_) is always true. This | 1409 // safe_browsing::IsSupportedBinaryFile(supported_path_) is always true. This |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1459 } | 1470 } |
| 1460 } | 1471 } |
| 1461 | 1472 |
| 1462 bool DownloadProtectionService::IsHashManuallyBlacklisted( | 1473 bool DownloadProtectionService::IsHashManuallyBlacklisted( |
| 1463 const std::string& sha256_hash) const { | 1474 const std::string& sha256_hash) const { |
| 1464 return manual_blacklist_hashes_.count(sha256_hash) > 0; | 1475 return manual_blacklist_hashes_.count(sha256_hash) > 0; |
| 1465 } | 1476 } |
| 1466 | 1477 |
| 1467 void DownloadProtectionService::CheckClientDownload( | 1478 void DownloadProtectionService::CheckClientDownload( |
| 1468 content::DownloadItem* item, | 1479 content::DownloadItem* item, |
| 1469 const CheckDownloadCallback& callback) { | 1480 const CheckDownloadContentCallback& callback) { |
| 1470 scoped_refptr<CheckClientDownloadRequest> request( | 1481 scoped_refptr<CheckClientDownloadRequest> request( |
| 1471 new CheckClientDownloadRequest(item, callback, this, | 1482 new CheckClientDownloadRequest(item, callback, this, |
| 1472 database_manager_, | 1483 database_manager_, |
| 1473 binary_feature_extractor_.get())); | 1484 binary_feature_extractor_.get())); |
| 1474 download_requests_.insert(request); | 1485 download_requests_.insert(request); |
| 1475 request->Start(); | 1486 request->Start(); |
| 1476 } | 1487 } |
| 1477 | 1488 |
| 1478 void DownloadProtectionService::CheckDownloadUrl( | 1489 void DownloadProtectionService::CheckDownloadUrl( |
| 1479 const content::DownloadItem& item, | 1490 const content::DownloadItem& item, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1496 ClientDownloadRequest::WIN_EXECUTABLE; | 1507 ClientDownloadRequest::WIN_EXECUTABLE; |
| 1497 return (CheckClientDownloadRequest::IsSupportedDownload( | 1508 return (CheckClientDownloadRequest::IsSupportedDownload( |
| 1498 item, target_path, &reason, &type) && | 1509 item, target_path, &reason, &type) && |
| 1499 (ClientDownloadRequest::CHROME_EXTENSION != type)); | 1510 (ClientDownloadRequest::CHROME_EXTENSION != type)); |
| 1500 } | 1511 } |
| 1501 | 1512 |
| 1502 void DownloadProtectionService::CheckPPAPIDownloadRequest( | 1513 void DownloadProtectionService::CheckPPAPIDownloadRequest( |
| 1503 const GURL& requestor_url, | 1514 const GURL& requestor_url, |
| 1504 const base::FilePath& default_file_path, | 1515 const base::FilePath& default_file_path, |
| 1505 const std::vector<base::FilePath::StringType>& alternate_extensions, | 1516 const std::vector<base::FilePath::StringType>& alternate_extensions, |
| 1506 const CheckDownloadCallback& callback) { | 1517 const CheckDownloadContentCallback& callback) { |
| 1507 DVLOG(1) << __FUNCTION__ << " url:" << requestor_url | 1518 DVLOG(1) << __FUNCTION__ << " url:" << requestor_url |
| 1508 << " default_file_path:" << default_file_path.value(); | 1519 << " default_file_path:" << default_file_path.value(); |
| 1509 std::unique_ptr<PPAPIDownloadRequest> request(new PPAPIDownloadRequest( | 1520 std::unique_ptr<PPAPIDownloadRequest> request(new PPAPIDownloadRequest( |
| 1510 requestor_url, default_file_path, alternate_extensions, callback, this, | 1521 requestor_url, default_file_path, alternate_extensions, callback, this, |
| 1511 database_manager_)); | 1522 database_manager_)); |
| 1512 PPAPIDownloadRequest* request_copy = request.get(); | 1523 PPAPIDownloadRequest* request_copy = request.get(); |
| 1513 auto insertion_result = ppapi_download_requests_.insert( | 1524 auto insertion_result = ppapi_download_requests_.insert( |
| 1514 std::make_pair(request_copy, std::move(request))); | 1525 std::make_pair(request_copy, std::move(request))); |
| 1515 DCHECK(insertion_result.second); | 1526 DCHECK(insertion_result.second); |
| 1516 insertion_result.first->second->Start(); | 1527 insertion_result.first->second->Start(); |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1649 GURL DownloadProtectionService::GetDownloadRequestUrl() { | 1660 GURL DownloadProtectionService::GetDownloadRequestUrl() { |
| 1650 GURL url(kDownloadRequestUrl); | 1661 GURL url(kDownloadRequestUrl); |
| 1651 std::string api_key = google_apis::GetAPIKey(); | 1662 std::string api_key = google_apis::GetAPIKey(); |
| 1652 if (!api_key.empty()) | 1663 if (!api_key.empty()) |
| 1653 url = url.Resolve("?key=" + net::EscapeQueryParamValue(api_key, true)); | 1664 url = url.Resolve("?key=" + net::EscapeQueryParamValue(api_key, true)); |
| 1654 | 1665 |
| 1655 return url; | 1666 return url; |
| 1656 } | 1667 } |
| 1657 | 1668 |
| 1658 } // namespace safe_browsing | 1669 } // namespace safe_browsing |
| OLD | NEW |