Index: chrome/browser/download/chrome_download_manager_delegate.cc |
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc |
index 3d1124992a444a9d249e0caa09d485d0fd7d4094..00580825c7dde76ec4a05700fcf5d9f2dab2bd5d 100644 |
--- a/chrome/browser/download/chrome_download_manager_delegate.cc |
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc |
@@ -16,6 +16,7 @@ |
#include "base/time.h" |
#include "base/utf_string_conversions.h" |
#include "chrome/browser/browser_process.h" |
+#include "chrome/browser/download/download_completion_blocker.h" |
#include "chrome/browser/download/download_crx_util.h" |
#include "chrome/browser/download/download_extensions.h" |
#include "chrome/browser/download/download_file_picker.h" |
@@ -70,13 +71,33 @@ namespace { |
static const char safe_browsing_id[] = "Safe Browsing ID"; |
// The state of a safebrowsing check. |
-struct SafeBrowsingState : public DownloadItem::ExternalData { |
- // If true the SafeBrowsing check is not done yet. |
- bool pending; |
- // The verdict that we got from calling CheckClientDownload. |
- safe_browsing::DownloadProtectionService::DownloadCheckResult verdict; |
+class SafeBrowsingState : public DownloadCompletionBlocker { |
+ public: |
+ SafeBrowsingState() |
+ : verdict_(DownloadProtectionService::SAFE) { |
+ } |
+ |
+ virtual ~SafeBrowsingState(); |
+ |
+ // The verdict that we got from calling CheckClientDownload. Only valid to |
+ // call if |is_complete()|. |
+ DownloadProtectionService::DownloadCheckResult verdict() const { |
+ return verdict_; |
+ } |
+ |
+ void SetVerdict(DownloadProtectionService::DownloadCheckResult result) { |
+ verdict_ = result; |
+ CompleteDownload(); |
+ } |
+ |
+ private: |
+ DownloadProtectionService::DownloadCheckResult verdict_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SafeBrowsingState); |
}; |
+SafeBrowsingState::~SafeBrowsingState() {} |
+ |
} // namespace |
ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate(Profile* profile) |
@@ -203,34 +224,28 @@ void ChromeDownloadManagerDelegate::DisableSafeBrowsing(DownloadItem* item) { |
#if defined(ENABLE_SAFE_BROWSING) |
SafeBrowsingState* state = static_cast<SafeBrowsingState*>( |
item->GetExternalData(&safe_browsing_id)); |
- DCHECK(state == NULL); |
- if (state == NULL) { |
+ DCHECK(!state); |
+ if (!state) |
state = new SafeBrowsingState(); |
- item->SetExternalData(&safe_browsing_id, state); |
- } |
- state->pending = false; |
- state->verdict = DownloadProtectionService::SAFE; |
+ state->SetVerdict(DownloadProtectionService::SAFE); |
+ item->SetExternalData(&safe_browsing_id, state); |
#endif |
} |
-bool ChromeDownloadManagerDelegate::ShouldCompleteDownload(DownloadItem* item) { |
+bool ChromeDownloadManagerDelegate::IsDownloadReadyForCompletion( |
+ DownloadItem* item, |
+ const base::Closure& internal_complete_callback) { |
#if defined(ENABLE_SAFE_BROWSING) |
- // See if there is already a pending SafeBrowsing check for that download. |
SafeBrowsingState* state = static_cast<SafeBrowsingState*>( |
item->GetExternalData(&safe_browsing_id)); |
- // Don't complete the download until we have an answer. |
- if (state && state->pending) |
- return false; |
- |
- if (state == NULL) { |
+ if (!state) { |
// Begin the safe browsing download protection check. |
DownloadProtectionService* service = GetDownloadProtectionService(); |
if (service) { |
VLOG(2) << __FUNCTION__ << "() Start SB download check for download = " |
<< item->DebugString(false); |
state = new SafeBrowsingState(); |
- state->pending = true; |
- state->verdict = DownloadProtectionService::SAFE; |
+ state->set_callback(internal_complete_callback); |
item->SetExternalData(&safe_browsing_id, state); |
service->CheckClientDownload( |
DownloadProtectionService::DownloadInfo::FromDownloadItem(*item), |
@@ -240,18 +255,50 @@ bool ChromeDownloadManagerDelegate::ShouldCompleteDownload(DownloadItem* item) { |
item->GetId())); |
return false; |
} |
+ } else if (!state->is_complete()) { |
+ // Don't complete the download until we have an answer. |
+ state->set_callback(internal_complete_callback); |
+ return false; |
} |
#endif |
#if defined(OS_CHROMEOS) |
// If there's a GData upload associated with this download, we wait until that |
// is complete before allowing the download item to complete. |
- if (!gdata::GDataDownloadObserver::IsReadyToComplete(item)) |
+ if (!gdata::GDataDownloadObserver::IsReadyToComplete( |
+ item, internal_complete_callback)) |
return false; |
#endif |
return true; |
} |
+// ShouldCompleteDownloadInternal() will never be called directly by a user, it |
+// will only be called asynchronously, so it should run |
+// |user_complete_callback|. ShouldCompleteDownload() will only be called |
+// directly by a user, so it does not need to run |user_complete_callback| |
+// because it can return true synchronously. The two methods look very similar, |
+// but their semantics are very different. |
+ |
+void ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal( |
+ int download_id, |
+ const base::Closure& user_complete_callback) { |
+ DownloadItem* item = download_manager_->GetActiveDownloadItem(download_id); |
+ if (!item) |
+ return; |
+ if (IsDownloadReadyForCompletion(item, base::Bind( |
+ &ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal, this, |
+ download_id, user_complete_callback))) |
+ user_complete_callback.Run(); |
+} |
+ |
+bool ChromeDownloadManagerDelegate::ShouldCompleteDownload( |
+ DownloadItem* item, |
+ const base::Closure& user_complete_callback) { |
+ return IsDownloadReadyForCompletion(item, base::Bind( |
+ &ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal, this, |
+ item->GetId(), user_complete_callback)); |
+} |
+ |
bool ChromeDownloadManagerDelegate::ShouldOpenDownload(DownloadItem* item) { |
if (IsExtensionDownload(item)) { |
// We can open extensions if either they came from the store, or |
@@ -473,12 +520,7 @@ void ChromeDownloadManagerDelegate::CheckClientDownloadDone( |
SafeBrowsingState* state = static_cast<SafeBrowsingState*>( |
item->GetExternalData(&safe_browsing_id)); |
- DCHECK(state); |
- if (state) { |
- state->pending = false; |
- state->verdict = result; |
- } |
- item->MaybeCompleteDownload(); |
+ state->SetVerdict(result); |
} |
// content::NotificationObserver implementation. |