OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/format_macros.h" | 8 #include "base/format_macros.h" |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
12 #include "base/string_number_conversions.h" | 12 #include "base/string_number_conversions.h" |
13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
14 #include "base/stringprintf.h" | 14 #include "base/stringprintf.h" |
15 #include "base/time.h" | 15 #include "base/time.h" |
16 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | 16 #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
17 #include "chrome/browser/safe_browsing/signature_util.h" | 17 #include "chrome/browser/safe_browsing/signature_util.h" |
18 #include "chrome/common/net/http_return.h" | 18 #include "chrome/common/net/http_return.h" |
19 #include "chrome/common/safe_browsing/csd.pb.h" | 19 #include "chrome/common/safe_browsing/csd.pb.h" |
20 #include "content/browser/download/download_item.h" | 20 #include "content/browser/download/download_item.h" |
21 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
22 #include "content/public/common/url_fetcher.h" | 22 #include "content/public/common/url_fetcher.h" |
23 #include "content/public/common/url_fetcher_delegate.h" | 23 #include "content/public/common/url_fetcher_delegate.h" |
24 #include "net/base/load_flags.h" | 24 #include "net/base/load_flags.h" |
25 #include "net/url_request/url_request_context_getter.h" | 25 #include "net/url_request/url_request_context_getter.h" |
26 #include "net/url_request/url_request_status.h" | 26 #include "net/url_request/url_request_status.h" |
27 | 27 |
28 using content::BrowserThread; | 28 using content::BrowserThread; |
29 | 29 |
30 namespace { | |
31 static const int64 kDownloadRequestTimeoutMs = 3000; | |
32 } // namespace | |
33 | |
30 namespace safe_browsing { | 34 namespace safe_browsing { |
31 | 35 |
32 const char DownloadProtectionService::kDownloadRequestUrl[] = | 36 const char DownloadProtectionService::kDownloadRequestUrl[] = |
33 "https://sb-ssl.google.com/safebrowsing/clientreport/download"; | 37 "https://sb-ssl.google.com/safebrowsing/clientreport/download"; |
34 | 38 |
35 namespace { | 39 namespace { |
36 bool IsBinaryFile(const FilePath& file) { | 40 bool IsBinaryFile(const FilePath& file) { |
37 return (file.MatchesExtension(FILE_PATH_LITERAL(".exe")) || | 41 return (file.MatchesExtension(FILE_PATH_LITERAL(".exe")) || |
38 file.MatchesExtension(FILE_PATH_LITERAL(".cab")) || | 42 file.MatchesExtension(FILE_PATH_LITERAL(".cab")) || |
39 file.MatchesExtension(FILE_PATH_LITERAL(".msi"))); | 43 file.MatchesExtension(FILE_PATH_LITERAL(".msi"))); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
137 | 141 |
138 // static | 142 // static |
139 DownloadProtectionService::DownloadInfo | 143 DownloadProtectionService::DownloadInfo |
140 DownloadProtectionService::DownloadInfo::FromDownloadItem( | 144 DownloadProtectionService::DownloadInfo::FromDownloadItem( |
141 const DownloadItem& item) { | 145 const DownloadItem& item) { |
142 DownloadInfo download_info; | 146 DownloadInfo download_info; |
143 download_info.local_file = item.full_path(); | 147 download_info.local_file = item.full_path(); |
144 download_info.target_file = item.GetTargetFilePath(); | 148 download_info.target_file = item.GetTargetFilePath(); |
145 download_info.download_url_chain = item.url_chain(); | 149 download_info.download_url_chain = item.url_chain(); |
146 download_info.referrer_url = item.referrer_url(); | 150 download_info.referrer_url = item.referrer_url(); |
147 // TODO(bryner): Fill in the hash (we shouldn't compute it again) | 151 download_info.sha256_hash = item.hash(); |
148 download_info.total_bytes = item.total_bytes(); | 152 download_info.total_bytes = item.total_bytes(); |
149 // TODO(bryner): Populate user_initiated | 153 // TODO(bryner): Populate user_initiated |
150 return download_info; | 154 return download_info; |
151 } | 155 } |
152 | 156 |
153 // Parent SafeBrowsing::Client class used to lookup the bad binary | 157 // Parent SafeBrowsing::Client class used to lookup the bad binary |
154 // URL and digest list. There are two sub-classes (one for each list). | 158 // URL and digest list. There are two sub-classes (one for each list). |
155 class DownloadSBClient | 159 class DownloadSBClient |
156 : public SafeBrowsingService::Client, | 160 : public SafeBrowsingService::Client, |
157 public base::RefCountedThreadSafe<DownloadSBClient> { | 161 public base::RefCountedThreadSafe<DownloadSBClient> { |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
325 CheckClientDownloadRequest(const DownloadInfo& info, | 329 CheckClientDownloadRequest(const DownloadInfo& info, |
326 const CheckDownloadCallback& callback, | 330 const CheckDownloadCallback& callback, |
327 DownloadProtectionService* service, | 331 DownloadProtectionService* service, |
328 SafeBrowsingService* sb_service, | 332 SafeBrowsingService* sb_service, |
329 SignatureUtil* signature_util) | 333 SignatureUtil* signature_util) |
330 : info_(info), | 334 : info_(info), |
331 callback_(callback), | 335 callback_(callback), |
332 service_(service), | 336 service_(service), |
333 signature_util_(signature_util), | 337 signature_util_(signature_util), |
334 sb_service_(sb_service), | 338 sb_service_(sb_service), |
335 pingback_enabled_(service_->enabled()) { | 339 pingback_enabled_(service_->enabled()), |
340 finished_(false) { | |
336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
337 } | 342 } |
338 | 343 |
339 void Start() { | 344 void Start() { |
340 VLOG(2) << "Starting SafeBrowsing download check for: " | 345 VLOG(2) << "Starting SafeBrowsing download check for: " |
341 << info_.DebugString(); | 346 << info_.DebugString(); |
342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
343 // TODO(noelutz): implement some cache to make sure we don't issue the same | 348 // TODO(noelutz): implement some cache to make sure we don't issue the same |
344 // request over and over again if a user downloads the same binary multiple | 349 // request over and over again if a user downloads the same binary multiple |
345 // times. | 350 // times. |
(...skipping 13 matching lines...) Expand all Loading... | |
359 if (final_url.SchemeIs("https") || !IsBinaryFile(info_.target_file)) { | 364 if (final_url.SchemeIs("https") || !IsBinaryFile(info_.target_file)) { |
360 RecordImprovedProtectionStats(final_url.SchemeIs("https") ? | 365 RecordImprovedProtectionStats(final_url.SchemeIs("https") ? |
361 REASON_HTTPS_URL : REASON_NOT_BINARY_FILE); | 366 REASON_HTTPS_URL : REASON_NOT_BINARY_FILE); |
362 BrowserThread::PostTask( | 367 BrowserThread::PostTask( |
363 BrowserThread::IO, | 368 BrowserThread::IO, |
364 FROM_HERE, | 369 FROM_HERE, |
365 base::Bind(&CheckClientDownloadRequest::CheckDigestList, this)); | 370 base::Bind(&CheckClientDownloadRequest::CheckDigestList, this)); |
366 return; | 371 return; |
367 } | 372 } |
368 | 373 |
374 // If the request takes too long we cancel it. | |
375 BrowserThread::PostDelayedTask( | |
376 BrowserThread::UI, | |
377 FROM_HERE, | |
378 base::Bind(&CheckClientDownloadRequest::Cancel, this), | |
379 service_->download_request_timeout_ms()); | |
380 | |
369 // Compute features from the file contents. Note that we record histograms | 381 // Compute features from the file contents. Note that we record histograms |
370 // based on the result, so this runs regardless of whether the pingbacks | 382 // based on the result, so this runs regardless of whether the pingbacks |
371 // are enabled. Since we do blocking I/O, this happens on the file thread. | 383 // are enabled. Since we do blocking I/O, this happens on the file thread. |
372 BrowserThread::PostTask( | 384 BrowserThread::PostTask( |
373 BrowserThread::FILE, | 385 BrowserThread::FILE, |
374 FROM_HERE, | 386 FROM_HERE, |
375 base::Bind(&CheckClientDownloadRequest::ExtractFileFeatures, this)); | 387 base::Bind(&CheckClientDownloadRequest::ExtractFileFeatures, this)); |
376 } | 388 } |
377 | 389 |
378 // Canceling a request will cause us to always report the result as SAFE. | 390 // Canceling a request will cause us to always report the result as SAFE. |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
545 return; | 557 return; |
546 } | 558 } |
547 | 559 |
548 VLOG(2) << "Sending a request for URL: " | 560 VLOG(2) << "Sending a request for URL: " |
549 << info_.download_url_chain.back(); | 561 << info_.download_url_chain.back(); |
550 fetcher_.reset(content::URLFetcher::Create(0 /* ID used for testing */, | 562 fetcher_.reset(content::URLFetcher::Create(0 /* ID used for testing */, |
551 GURL(kDownloadRequestUrl), | 563 GURL(kDownloadRequestUrl), |
552 content::URLFetcher::POST, | 564 content::URLFetcher::POST, |
553 this)); | 565 this)); |
554 fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE); | 566 fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE); |
567 fetcher_->SetAutomaticallyRetryOn5xx(false); // Don't retry on error. | |
555 fetcher_->SetRequestContext(service_->request_context_getter_.get()); | 568 fetcher_->SetRequestContext(service_->request_context_getter_.get()); |
556 fetcher_->SetUploadData("application/octet-stream", request_data); | 569 fetcher_->SetUploadData("application/octet-stream", request_data); |
557 fetcher_->Start(); | 570 fetcher_->Start(); |
558 } | 571 } |
559 | 572 |
560 void PostFinishTask(DownloadCheckResult result) { | 573 void PostFinishTask(DownloadCheckResult result) { |
561 BrowserThread::PostTask( | 574 BrowserThread::PostTask( |
562 BrowserThread::UI, | 575 BrowserThread::UI, |
563 FROM_HERE, | 576 FROM_HERE, |
564 base::Bind(&CheckClientDownloadRequest::FinishRequest, this, result)); | 577 base::Bind(&CheckClientDownloadRequest::FinishRequest, this, result)); |
565 } | 578 } |
566 | 579 |
567 void FinishRequest(DownloadCheckResult result) { | 580 void FinishRequest(DownloadCheckResult result) { |
568 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 581 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
582 if (finished_) { | |
583 return; | |
Brian Ryner
2011/11/17 02:07:03
I don't think this will remove the request from do
| |
584 } | |
585 finished_ = true; | |
569 if (service_) { | 586 if (service_) { |
570 callback_.Run(result); | 587 callback_.Run(result); |
571 service_->RequestFinished(this); | 588 service_->RequestFinished(this); |
572 } else { | 589 } else { |
573 callback_.Run(SAFE); | 590 callback_.Run(SAFE); |
574 } | 591 } |
575 } | 592 } |
576 | 593 |
577 void RecordImprovedProtectionStats(DownloadCheckResultReason reason) { | 594 void RecordImprovedProtectionStats(DownloadCheckResultReason reason) { |
578 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", | 595 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", |
579 reason, | 596 reason, |
580 REASON_MAX); | 597 REASON_MAX); |
581 } | 598 } |
582 | 599 |
583 DownloadInfo info_; | 600 DownloadInfo info_; |
584 ClientDownloadRequest_SignatureInfo signature_info_; | 601 ClientDownloadRequest_SignatureInfo signature_info_; |
585 CheckDownloadCallback callback_; | 602 CheckDownloadCallback callback_; |
586 // Will be NULL if the request has been canceled. | 603 // Will be NULL if the request has been canceled. |
587 DownloadProtectionService* service_; | 604 DownloadProtectionService* service_; |
588 scoped_refptr<SignatureUtil> signature_util_; | 605 scoped_refptr<SignatureUtil> signature_util_; |
589 scoped_refptr<SafeBrowsingService> sb_service_; | 606 scoped_refptr<SafeBrowsingService> sb_service_; |
590 const bool pingback_enabled_; | 607 const bool pingback_enabled_; |
591 scoped_ptr<content::URLFetcher> fetcher_; | 608 scoped_ptr<content::URLFetcher> fetcher_; |
609 bool finished_; | |
592 | 610 |
593 DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest); | 611 DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest); |
594 }; | 612 }; |
595 | 613 |
596 DownloadProtectionService::DownloadProtectionService( | 614 DownloadProtectionService::DownloadProtectionService( |
597 SafeBrowsingService* sb_service, | 615 SafeBrowsingService* sb_service, |
598 net::URLRequestContextGetter* request_context_getter) | 616 net::URLRequestContextGetter* request_context_getter) |
599 : sb_service_(sb_service), | 617 : sb_service_(sb_service), |
600 request_context_getter_(request_context_getter), | 618 request_context_getter_(request_context_getter), |
601 enabled_(false), | 619 enabled_(false), |
602 signature_util_(new SignatureUtil()) {} | 620 signature_util_(new SignatureUtil()), |
621 download_request_timeout_ms_(kDownloadRequestTimeoutMs) {} | |
603 | 622 |
604 DownloadProtectionService::~DownloadProtectionService() { | 623 DownloadProtectionService::~DownloadProtectionService() { |
605 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 624 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
606 CancelPendingRequests(); | 625 CancelPendingRequests(); |
607 } | 626 } |
608 | 627 |
609 void DownloadProtectionService::SetEnabled(bool enabled) { | 628 void DownloadProtectionService::SetEnabled(bool enabled) { |
610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 629 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
611 if (enabled == enabled_) { | 630 if (enabled == enabled_) { |
612 return; | 631 return; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
652 | 671 |
653 void DownloadProtectionService::RequestFinished( | 672 void DownloadProtectionService::RequestFinished( |
654 CheckClientDownloadRequest* request) { | 673 CheckClientDownloadRequest* request) { |
655 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 674 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
656 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = | 675 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = |
657 download_requests_.find(request); | 676 download_requests_.find(request); |
658 DCHECK(it != download_requests_.end()); | 677 DCHECK(it != download_requests_.end()); |
659 download_requests_.erase(*it); | 678 download_requests_.erase(*it); |
660 } | 679 } |
661 } // namespace safe_browsing | 680 } // namespace safe_browsing |
OLD | NEW |