| Index: chrome/browser/safe_browsing/download_protection_service.cc
|
| diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
|
| index 71fa9c3e71d3638eec0041145ec6af4bdc6f01f0..cba4da13ee7970bb10a19e2e63964461a3936622 100644
|
| --- a/chrome/browser/safe_browsing/download_protection_service.cc
|
| +++ b/chrome/browser/safe_browsing/download_protection_service.cc
|
| @@ -5,8 +5,10 @@
|
| #include "chrome/browser/safe_browsing/download_protection_service.h"
|
|
|
| #include "base/bind.h"
|
| +#include "base/compiler_specific.h"
|
| #include "base/format_macros.h"
|
| #include "base/memory/scoped_ptr.h"
|
| +#include "base/memory/weak_ptr.h"
|
| #include "base/metrics/histogram.h"
|
| #include "base/stl_util.h"
|
| #include "base/string_number_conversions.h"
|
| @@ -27,6 +29,10 @@
|
|
|
| using content::BrowserThread;
|
|
|
| +namespace {
|
| +static const int64 kDownloadRequestTimeoutMs = 3000;
|
| +} // namespace
|
| +
|
| namespace safe_browsing {
|
|
|
| const char DownloadProtectionService::kDownloadRequestUrl[] =
|
| @@ -144,7 +150,7 @@ DownloadProtectionService::DownloadInfo::FromDownloadItem(
|
| download_info.target_file = item.GetTargetFilePath();
|
| download_info.download_url_chain = item.url_chain();
|
| download_info.referrer_url = item.referrer_url();
|
| - // TODO(bryner): Fill in the hash (we shouldn't compute it again)
|
| + download_info.sha256_hash = item.hash();
|
| download_info.total_bytes = item.total_bytes();
|
| // TODO(bryner): Populate user_initiated
|
| return download_info;
|
| @@ -332,7 +338,9 @@ class DownloadProtectionService::CheckClientDownloadRequest
|
| service_(service),
|
| signature_util_(signature_util),
|
| sb_service_(sb_service),
|
| - pingback_enabled_(service_->enabled()) {
|
| + pingback_enabled_(service_->enabled()),
|
| + finished_(false),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(timeout_weakptr_factory_(this)) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| }
|
|
|
| @@ -373,24 +381,35 @@ class DownloadProtectionService::CheckClientDownloadRequest
|
| BrowserThread::FILE,
|
| FROM_HERE,
|
| base::Bind(&CheckClientDownloadRequest::ExtractFileFeatures, this));
|
| +
|
| + // If the request takes too long we cancel it.
|
| + BrowserThread::PostDelayedTask(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(&CheckClientDownloadRequest::Cancel,
|
| + timeout_weakptr_factory_.GetWeakPtr()),
|
| + service_->download_request_timeout_ms());
|
| }
|
|
|
| - // Canceling a request will cause us to always report the result as SAFE.
|
| - // In addition, the DownloadProtectionService will not be notified when the
|
| - // request finishes, so it must drop its reference after calling Cancel.
|
| + // Canceling a request will cause us to always report the result as SAFE
|
| + // unless a pending request is about to call FinishRequest.
|
| void Cancel() {
|
| + // Calling FinishRequest might delete this object if we don't keep a
|
| + // reference around until Cancel() is finished running.
|
| + scoped_refptr<CheckClientDownloadRequest> request(this);
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - service_ = NULL;
|
| + FinishRequest(SAFE);
|
| if (fetcher_.get()) {
|
| // The DownloadProtectionService is going to release its reference, so we
|
| // might be destroyed before the URLFetcher completes. Cancel the
|
| // fetcher so it does not try to invoke OnURLFetchComplete.
|
| - FinishRequest(SAFE);
|
| fetcher_.reset();
|
| }
|
| // Note: If there is no fetcher, then some callback is still holding a
|
| // reference to this object. We'll eventually wind up in some method on
|
| - // the UI thread that will call FinishRequest() and run the callback.
|
| + // the UI thread that will call FinishRequest() again. If FinishRequest()
|
| + // is called a second time, it will be a no-op.
|
| + service_ = NULL;
|
| }
|
|
|
| // From the content::URLFetcherDelegate interface.
|
| @@ -552,6 +571,7 @@ class DownloadProtectionService::CheckClientDownloadRequest
|
| content::URLFetcher::POST,
|
| this));
|
| fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE);
|
| + fetcher_->SetAutomaticallyRetryOn5xx(false); // Don't retry on error.
|
| fetcher_->SetRequestContext(service_->request_context_getter_.get());
|
| fetcher_->SetUploadData("application/octet-stream", request_data);
|
| fetcher_->Start();
|
| @@ -566,6 +586,10 @@ class DownloadProtectionService::CheckClientDownloadRequest
|
|
|
| void FinishRequest(DownloadCheckResult result) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + if (finished_) {
|
| + return;
|
| + }
|
| + finished_ = true;
|
| if (service_) {
|
| callback_.Run(result);
|
| service_->RequestFinished(this);
|
| @@ -589,6 +613,8 @@ class DownloadProtectionService::CheckClientDownloadRequest
|
| scoped_refptr<SafeBrowsingService> sb_service_;
|
| const bool pingback_enabled_;
|
| scoped_ptr<content::URLFetcher> fetcher_;
|
| + bool finished_;
|
| + base::WeakPtrFactory<CheckClientDownloadRequest> timeout_weakptr_factory_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest);
|
| };
|
| @@ -599,7 +625,8 @@ DownloadProtectionService::DownloadProtectionService(
|
| : sb_service_(sb_service),
|
| request_context_getter_(request_context_getter),
|
| enabled_(false),
|
| - signature_util_(new SignatureUtil()) {}
|
| + signature_util_(new SignatureUtil()),
|
| + download_request_timeout_ms_(kDownloadRequestTimeoutMs) {}
|
|
|
| DownloadProtectionService::~DownloadProtectionService() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| @@ -644,10 +671,13 @@ void DownloadProtectionService::CancelPendingRequests() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| for (std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it =
|
| download_requests_.begin();
|
| - it != download_requests_.end(); ++it) {
|
| - (*it)->Cancel();
|
| + it != download_requests_.end();) {
|
| + // We need to advance the iterator before we cancel because canceling
|
| + // the request will invalidate it when RequestFinished is called below.
|
| + scoped_refptr<CheckClientDownloadRequest> tmp = *it++;
|
| + tmp->Cancel();
|
| }
|
| - download_requests_.clear();
|
| + DCHECK(download_requests_.empty());
|
| }
|
|
|
| void DownloadProtectionService::RequestFinished(
|
|
|