| Index: chrome/browser/download/download_manager.cc
|
| diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc
|
| index c61912a27dab764060b2dd4e824dca69c84f7245..4d7db4a8f21263f125597bd757f44437bbbcc909 100644
|
| --- a/chrome/browser/download/download_manager.cc
|
| +++ b/chrome/browser/download/download_manager.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "chrome/browser/download/download_manager.h"
|
|
|
| +#include "base/bind.h"
|
| #include "base/callback.h"
|
| #include "base/file_util.h"
|
| #include "base/i18n/case_conversion.h"
|
| @@ -23,6 +24,7 @@
|
| #include "chrome/browser/download/download_history.h"
|
| #include "chrome/browser/download/download_item.h"
|
| #include "chrome/browser/download/download_prefs.h"
|
| +#include "chrome/browser/download/download_query.h"
|
| #include "chrome/browser/download/download_request_handle.h"
|
| #include "chrome/browser/download/download_safe_browsing_client.h"
|
| #include "chrome/browser/download/download_status_updater.h"
|
| @@ -84,49 +86,18 @@ void DownloadManager::Shutdown() {
|
|
|
| AssertContainersConsistent();
|
|
|
| - // Go through all downloads in downloads_. Dangerous ones we need to
|
| - // remove on disk, and in progress ones we need to cancel.
|
| - for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
|
| - DownloadItem* download = *it;
|
| -
|
| - // Save iterator from potential erases in this set done by called code.
|
| - // Iterators after an erasure point are still valid for lists and
|
| - // associative containers such as sets.
|
| - it++;
|
| -
|
| + for (DownloadMap::iterator it = downloads_.begin(); it != downloads_.end();) {
|
| + DownloadItem* download = it->second;
|
| + ++it;
|
| if (download->safety_state() == DownloadItem::DANGEROUS &&
|
| download->IsPartialDownload()) {
|
| - // The user hasn't accepted it, so we need to remove it
|
| - // from the disk. This may or may not result in it being
|
| - // removed from the DownloadManager queues and deleted
|
| - // (specifically, DownloadManager::RemoveDownload only
|
| - // removes and deletes it if it's known to the history service)
|
| - // so the only thing we know after calling this function is that
|
| - // the download was deleted if-and-only-if it was removed
|
| - // from all queues.
|
| download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
|
| } else if (download->IsPartialDownload()) {
|
| download->Cancel(false);
|
| download_history_->UpdateEntry(download);
|
| }
|
| }
|
| -
|
| - // At this point, all dangerous downloads have had their files removed
|
| - // and all in progress downloads have been cancelled. We can now delete
|
| - // anything left.
|
| -
|
| - // Copy downloads_ to separate container so as not to set off checks
|
| - // in DownloadItem destruction.
|
| - DownloadSet downloads_to_delete;
|
| - downloads_to_delete.swap(downloads_);
|
| -
|
| - in_progress_.clear();
|
| - active_downloads_.clear();
|
| - history_downloads_.clear();
|
| -#if !defined(NDEBUG)
|
| - save_page_as_downloads_.clear();
|
| -#endif
|
| - STLDeleteElements(&downloads_to_delete);
|
| + STLValueDeleter<DownloadMap> delete_items(&downloads_);
|
|
|
| file_manager_ = NULL;
|
|
|
| @@ -137,90 +108,6 @@ void DownloadManager::Shutdown() {
|
|
|
| download_history_.reset();
|
| download_prefs_.reset();
|
| -
|
| - shutdown_needed_ = false;
|
| -}
|
| -
|
| -void DownloadManager::GetTemporaryDownloads(
|
| - const FilePath& dir_path, std::vector<DownloadItem*>* result) {
|
| - DCHECK(result);
|
| -
|
| - for (DownloadMap::iterator it = history_downloads_.begin();
|
| - it != history_downloads_.end(); ++it) {
|
| - if (it->second->is_temporary() &&
|
| - it->second->full_path().DirName() == dir_path)
|
| - result->push_back(it->second);
|
| - }
|
| -}
|
| -
|
| -void DownloadManager::GetAllDownloads(
|
| - const FilePath& dir_path, std::vector<DownloadItem*>* result) {
|
| - DCHECK(result);
|
| -
|
| - for (DownloadMap::iterator it = history_downloads_.begin();
|
| - it != history_downloads_.end(); ++it) {
|
| - if (!it->second->is_temporary() &&
|
| - (dir_path.empty() || it->second->full_path().DirName() == dir_path))
|
| - result->push_back(it->second);
|
| - }
|
| -}
|
| -
|
| -void DownloadManager::GetCurrentDownloads(
|
| - const FilePath& dir_path, std::vector<DownloadItem*>* result) {
|
| - DCHECK(result);
|
| -
|
| - for (DownloadMap::iterator it = history_downloads_.begin();
|
| - it != history_downloads_.end(); ++it) {
|
| - DownloadItem* item =it->second;
|
| - // Skip temporary items.
|
| - if (item->is_temporary())
|
| - continue;
|
| - // Skip items that have all their data, and are OK to save.
|
| - if (!item->IsPartialDownload() &&
|
| - (item->safety_state() != DownloadItem::DANGEROUS))
|
| - continue;
|
| - // Skip items that don't match |dir_path|.
|
| - // If |dir_path| is empty, all remaining items match.
|
| - if (!dir_path.empty() && (it->second->full_path().DirName() != dir_path))
|
| - continue;
|
| -
|
| - result->push_back(item);
|
| - }
|
| -
|
| - // If we have a parent profile, let it add its downloads to the results.
|
| - Profile* original_profile = profile_->GetOriginalProfile();
|
| - if (original_profile != profile_)
|
| - original_profile->GetDownloadManager()->GetCurrentDownloads(dir_path,
|
| - result);
|
| -}
|
| -
|
| -void DownloadManager::SearchDownloads(const string16& query,
|
| - std::vector<DownloadItem*>* result) {
|
| - DCHECK(result);
|
| -
|
| - string16 query_lower(base::i18n::ToLower(query));
|
| -
|
| - for (DownloadMap::iterator it = history_downloads_.begin();
|
| - it != history_downloads_.end(); ++it) {
|
| - DownloadItem* download_item = it->second;
|
| -
|
| - if (download_item->is_temporary() || download_item->is_extension_install())
|
| - continue;
|
| -
|
| - // Display Incognito downloads only in Incognito window, and vice versa.
|
| - // The Incognito Downloads page will get the list of non-Incognito downloads
|
| - // from its parent profile.
|
| - if (profile_->IsOffTheRecord() != download_item->is_otr())
|
| - continue;
|
| -
|
| - if (download_item->MatchesQuery(query_lower))
|
| - result->push_back(download_item);
|
| - }
|
| -
|
| - // If we have a parent profile, let it add its downloads to the results.
|
| - Profile* original_profile = profile_->GetOriginalProfile();
|
| - if (original_profile != profile_)
|
| - original_profile->GetDownloadManager()->SearchDownloads(query, result);
|
| }
|
|
|
| // Query the history service for information about all persisted downloads.
|
| @@ -263,6 +150,7 @@ void DownloadManager::StartDownload(int32 download_id) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| DownloadItem* download = GetActiveDownloadItem(download_id);
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id << " " << download;
|
| if (!download)
|
| return;
|
|
|
| @@ -280,8 +168,9 @@ void DownloadManager::StartDownload(int32 download_id) {
|
|
|
| void DownloadManager::CheckForHistoryFilesRemoval() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - for (DownloadMap::iterator it = history_downloads_.begin();
|
| - it != history_downloads_.end(); ++it) {
|
| + DVLOG(1) << __PRETTY_FUNCTION__;
|
| + for (DownloadMap::iterator it = downloads_.begin();
|
| + it != downloads_.end(); ++it) {
|
| CheckForFileRemoval(it->second);
|
| }
|
| }
|
| @@ -294,27 +183,30 @@ void DownloadManager::CheckForFileRemoval(DownloadItem* download_item) {
|
| BrowserThread::FILE, FROM_HERE,
|
| NewRunnableMethod(this,
|
| &DownloadManager::CheckForFileRemovalOnFileThread,
|
| - download_item->db_handle(),
|
| + download_item->id(),
|
| download_item->GetTargetFilePath()));
|
| }
|
| }
|
|
|
| void DownloadManager::CheckForFileRemovalOnFileThread(
|
| - int64 db_handle, const FilePath& path) {
|
| + int64 id, const FilePath& path) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| if (!file_util::PathExists(path)) {
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << id;
|
| BrowserThread::PostTask(
|
| BrowserThread::UI, FROM_HERE,
|
| NewRunnableMethod(this,
|
| &DownloadManager::OnFileRemovalDetected,
|
| - db_handle));
|
| + id));
|
| }
|
| }
|
|
|
| -void DownloadManager::OnFileRemovalDetected(int64 db_handle) {
|
| +void DownloadManager::OnFileRemovalDetected(int64 id) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - DownloadMap::iterator it = history_downloads_.find(db_handle);
|
| - if (it != history_downloads_.end()) {
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << id;
|
| + DownloadMap::iterator it = downloads_.find(id);
|
| + if (it != downloads_.end()) {
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << id;
|
| DownloadItem* download_item = it->second;
|
| download_item->OnDownloadedFileRemoved();
|
| }
|
| @@ -325,6 +217,8 @@ void DownloadManager::CheckDownloadUrlDone(int32 download_id,
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| DownloadItem* download = GetActiveDownloadItem(download_id);
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id << " "
|
| + << is_dangerous_url << " " << download;
|
| if (!download)
|
| return;
|
|
|
| @@ -342,6 +236,7 @@ void DownloadManager::CheckVisitedReferrerBeforeDone(
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| DownloadItem* download = GetActiveDownloadItem(download_id);
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id << " " << download;
|
| if (!download)
|
| return;
|
|
|
| @@ -418,6 +313,7 @@ void DownloadManager::CheckIfSuggestedPathExists(int32 download_id,
|
| DownloadStateInfo state,
|
| const FilePath& default_path) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id;
|
|
|
| // Make sure the default download directory exists.
|
| // TODO(phajdan.jr): only create the directory when we're sure the user
|
| @@ -508,6 +404,7 @@ void DownloadManager::OnPathExistenceAvailable(
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| DownloadItem* download = GetActiveDownloadItem(download_id);
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download << " " << download_id;
|
| if (!download)
|
| return;
|
|
|
| @@ -558,11 +455,11 @@ void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info) {
|
|
|
| DownloadItem* download = new DownloadItem(this, *info,
|
| profile_->IsOffTheRecord());
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << info->download_id << " "
|
| + << download;
|
| int32 download_id = info->download_id;
|
| - DCHECK(!ContainsKey(in_progress_, download_id));
|
| - DCHECK(!ContainsKey(active_downloads_, download_id));
|
| - downloads_.insert(download);
|
| - active_downloads_[download_id] = download;
|
| + DCHECK(!ContainsKey(downloads_, download_id));
|
| + downloads_[download_id] = download;
|
| }
|
|
|
| void DownloadManager::ContinueDownloadWithPath(DownloadItem* download,
|
| @@ -571,12 +468,8 @@ void DownloadManager::ContinueDownloadWithPath(DownloadItem* download,
|
| DCHECK(download);
|
|
|
| int32 download_id = download->id();
|
| -
|
| - // NOTE(ahendrickson) Eventually |active_downloads_| will replace
|
| - // |in_progress_|, but we don't want to change the semantics yet.
|
| - DCHECK(!ContainsKey(in_progress_, download_id));
|
| - DCHECK(ContainsKey(downloads_, download));
|
| - DCHECK(ContainsKey(active_downloads_, download_id));
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id << " " << download
|
| + << " " << chosen_file.value();
|
|
|
| // Make sure the initial file name is set only once.
|
| DCHECK(download->full_path().empty());
|
| @@ -586,8 +479,7 @@ void DownloadManager::ContinueDownloadWithPath(DownloadItem* download,
|
| VLOG(20) << __FUNCTION__ << "()"
|
| << " download = " << download->DebugString(true);
|
|
|
| - in_progress_[download_id] = download;
|
| - UpdateAppIcon(); // Reflect entry into in_progress_.
|
| + UpdateAppIcon(); // Reflect entry into .
|
|
|
| // Rename to intermediate name.
|
| FilePath download_path;
|
| @@ -620,8 +512,8 @@ void DownloadManager::ContinueDownloadWithPath(DownloadItem* download,
|
|
|
| void DownloadManager::UpdateDownload(int32 download_id, int64 size) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - DownloadMap::iterator it = active_downloads_.find(download_id);
|
| - if (it != active_downloads_.end()) {
|
| + DownloadMap::iterator it = downloads_.find(download_id);
|
| + if (it != downloads_.end()) {
|
| DownloadItem* download = it->second;
|
| if (download->IsInProgress()) {
|
| download->Update(size);
|
| @@ -653,16 +545,16 @@ void DownloadManager::OnResponseCompleted(int32 download_id,
|
| void DownloadManager::OnAllDataSaved(int32 download_id,
|
| int64 size,
|
| const std::string& hash) {
|
| - VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
|
| + DVLOG(1) << __FUNCTION__ << "()" << " download_id = " << download_id
|
| << " size = " << size;
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| - // If it's not in active_downloads_, that means it was cancelled; just
|
| - // ignore the notification.
|
| - if (active_downloads_.count(download_id) == 0)
|
| + DownloadItem* download = downloads_[download_id];
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id << " " << size << " "
|
| + << hash << " " << download;
|
| + if (!download) {
|
| return;
|
| -
|
| - DownloadItem* download = active_downloads_[download_id];
|
| + }
|
| download->OnAllDataSaved(size);
|
|
|
| // When hash is not available, it means either it is not calculated
|
| @@ -691,48 +583,20 @@ void DownloadManager::CheckDownloadHashDone(int32 download_id,
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| DVLOG(1) << "CheckDownloadHashDone, download_id: " << download_id
|
| << " is dangerous_hash: " << is_dangerous_hash;
|
| -
|
| - // If it's not in active_downloads_, that means it was cancelled or
|
| - // the download already finished.
|
| - if (active_downloads_.count(download_id) == 0)
|
| - return;
|
| -
|
| - DVLOG(1) << "CheckDownloadHashDone, url: "
|
| - << active_downloads_[download_id]->GetURL().spec();
|
| }
|
|
|
| void DownloadManager::AssertQueueStateConsistent(DownloadItem* download) {
|
| - // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
|
| - if (download->state() == DownloadItem::REMOVING) {
|
| - CHECK(!ContainsKey(downloads_, download));
|
| - CHECK(!ContainsKey(active_downloads_, download->id()));
|
| - CHECK(!ContainsKey(in_progress_, download->id()));
|
| - CHECK(!ContainsKey(history_downloads_, download->db_handle()));
|
| - return;
|
| - }
|
| -
|
| - // Should be in downloads_ if we're not REMOVING.
|
| - CHECK(ContainsKey(downloads_, download));
|
| -
|
| - // Check history_downloads_ consistency.
|
| - if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
|
| - CHECK(ContainsKey(history_downloads_, download->db_handle()));
|
| - } else {
|
| - // TODO(rdsmith): Somewhat painful; make sure to disable in
|
| - // release builds after resolution of http://crbug.com/85408.
|
| - for (DownloadMap::iterator it = history_downloads_.begin();
|
| - it != history_downloads_.end(); ++it) {
|
| - CHECK(it->second != download);
|
| - }
|
| - }
|
| -
|
| - CHECK(ContainsKey(active_downloads_, download->id()) ==
|
| - (download->state() == DownloadItem::IN_PROGRESS));
|
| - CHECK(ContainsKey(in_progress_, download->id()) ==
|
| - (download->state() == DownloadItem::IN_PROGRESS));
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download;
|
| }
|
|
|
| bool DownloadManager::IsDownloadReadyForCompletion(DownloadItem* download) {
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " p=" << download << " id="
|
| + << download->id() << " data=" << download->all_data_saved()
|
| + << " safety=" << download->safety_state() << " path="
|
| + << download->full_path().value();
|
| + return download->all_data_saved() &&
|
| + download->safety_state() != DownloadItem::DANGEROUS &&
|
| + !download->full_path().value().empty();
|
| // If we don't have all the data, the download is not ready for
|
| // completion.
|
| if (!download->all_data_saved())
|
| @@ -743,24 +607,12 @@ bool DownloadManager::IsDownloadReadyForCompletion(DownloadItem* download) {
|
| if (download->safety_state() == DownloadItem::DANGEROUS)
|
| return false;
|
|
|
| - // If the download isn't active (e.g. has been cancelled) it's not
|
| - // ready for completion.
|
| - if (active_downloads_.count(download->id()) == 0)
|
| - return false;
|
| -
|
| - // If the download hasn't been inserted into the history system
|
| - // (which occurs strictly after file name determination, intermediate
|
| - // file rename, and UI display) then it's not ready for completion.
|
| - if (download->db_handle() == DownloadHistory::kUninitializedHandle)
|
| - return false;
|
| -
|
| return true;
|
| }
|
|
|
| void DownloadManager::MaybeCompleteDownload(DownloadItem* download) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - VLOG(20) << __FUNCTION__ << "()" << " download = "
|
| - << download->DebugString(false);
|
| + DVLOG(1) << __FUNCTION__ << " " << download->DebugString(true);
|
|
|
| if (!IsDownloadReadyForCompletion(download))
|
| return;
|
| @@ -770,24 +622,20 @@ void DownloadManager::MaybeCompleteDownload(DownloadItem* download) {
|
| // transition on the DownloadItem.
|
|
|
| // Confirm we're in the proper set of states to be here;
|
| - // in in_progress_, have all data, have a history handle, (validated or safe).
|
| + // in , have all data, have a history handle, (validated or safe).
|
| DCHECK_NE(DownloadItem::DANGEROUS, download->safety_state());
|
| - DCHECK_EQ(1u, in_progress_.count(download->id()));
|
| DCHECK(download->all_data_saved());
|
| - DCHECK(download->db_handle() != DownloadHistory::kUninitializedHandle);
|
| - DCHECK_EQ(1u, history_downloads_.count(download->db_handle()));
|
| + DCHECK(!download->full_path().value().empty());
|
|
|
| - VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
|
| - << download->DebugString(false);
|
| + DVLOG(1) << __FUNCTION__ << " " << download->DebugString(true);
|
|
|
| - // Remove the id from in_progress
|
| - in_progress_.erase(download->id());
|
| - UpdateAppIcon(); // Reflect removal from in_progress_.
|
| + UpdateAppIcon(); // Reflect removal from .
|
|
|
| download_history_->UpdateEntry(download);
|
|
|
| // Finish the download.
|
| download->OnDownloadCompleting(file_manager_);
|
| + DVLOG(1) << __FUNCTION__ << " " << download->DebugString(true);
|
| }
|
|
|
| void DownloadManager::DownloadCompleted(int32 download_id) {
|
| @@ -795,13 +643,12 @@ void DownloadManager::DownloadCompleted(int32 download_id) {
|
| DownloadItem* download = GetDownloadItem(download_id);
|
| DCHECK(download);
|
| download_history_->UpdateEntry(download);
|
| - active_downloads_.erase(download_id);
|
| }
|
|
|
| void DownloadManager::OnDownloadRenamedToFinalName(int download_id,
|
| const FilePath& full_path,
|
| int uniquifier) {
|
| - VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
|
| + DVLOG(1) << __FUNCTION__ << "()" << " download_id = " << download_id
|
| << " full_path = \"" << full_path.value() << "\""
|
| << " uniquifier = " << uniquifier;
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| @@ -824,27 +671,17 @@ void DownloadManager::OnDownloadRenamedToFinalName(int download_id,
|
|
|
| item->OnDownloadRenamedToFinalName(full_path);
|
| download_history_->UpdateDownloadPath(item, full_path);
|
| + UpdateAppIcon();
|
| }
|
|
|
| void DownloadManager::DownloadCancelled(int32 download_id) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - DownloadMap::iterator it = in_progress_.find(download_id);
|
| - if (it == in_progress_.end())
|
| - return;
|
| - DownloadItem* download = it->second;
|
| -
|
| - VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
|
| - << " download = " << download->DebugString(true);
|
| -
|
| - // Clean up will happen when the history system create callback runs if we
|
| - // don't have a valid db_handle yet.
|
| - if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
|
| - in_progress_.erase(it);
|
| - active_downloads_.erase(download_id);
|
| - UpdateAppIcon(); // Reflect removal from in_progress_.
|
| - download_history_->UpdateEntry(download);
|
| - }
|
| -
|
| + DownloadItem* download = downloads_[download_id];
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id << " " << download
|
| + << " " << (download ? download->DebugString(true) : "");
|
| + DCHECK(download);
|
| + UpdateAppIcon(); // Reflect removal from .
|
| + download_history_->UpdateEntry(download);
|
| DownloadCancelledInternal(download_id, download->request_handle());
|
| }
|
|
|
| @@ -863,32 +700,13 @@ void DownloadManager::OnDownloadError(int32 download_id,
|
| int64 size,
|
| int os_error) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - DownloadMap::iterator it = active_downloads_.find(download_id);
|
| - // A cancel at the right time could remove the download from the
|
| - // |active_downloads_| map before we get here.
|
| - if (it == active_downloads_.end())
|
| - return;
|
| -
|
| - DownloadItem* download = it->second;
|
| -
|
| - VLOG(20) << __FUNCTION__ << "()" << " Error " << os_error
|
| - << " at offset " << download->received_bytes()
|
| - << " for download = " << download->DebugString(true);
|
| -
|
| + DownloadItem* download = downloads_[download_id];
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id << " " << download
|
| + << " " << (download ? download->DebugString(true) : "");
|
| + DCHECK(download);
|
| download->Interrupted(size, os_error);
|
| -
|
| - // TODO(ahendrickson) - Remove this when we add resuming of interrupted
|
| - // downloads, as we will keep the download item around in that case.
|
| - //
|
| - // Clean up will happen when the history system create callback runs if we
|
| - // don't have a valid db_handle yet.
|
| - if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
|
| - in_progress_.erase(download_id);
|
| - active_downloads_.erase(download_id);
|
| - UpdateAppIcon(); // Reflect removal from in_progress_.
|
| - download_history_->UpdateEntry(download);
|
| - }
|
| -
|
| + UpdateAppIcon(); // Reflect removal from .
|
| + download_history_->UpdateEntry(download);
|
| BrowserThread::PostTask(
|
| BrowserThread::FILE, FROM_HERE,
|
| NewRunnableMethod(
|
| @@ -900,74 +718,108 @@ void DownloadManager::UpdateAppIcon() {
|
| status_updater_->Update();
|
| }
|
|
|
| -void DownloadManager::RemoveDownload(int64 download_handle) {
|
| - DownloadMap::iterator it = history_downloads_.find(download_handle);
|
| - if (it == history_downloads_.end())
|
| +void DownloadManager::RemoveDownload(int64 id) {
|
| + DownloadMap::iterator it = downloads_.find(id);
|
| + scoped_ptr<DownloadItem> download(it->second);
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << id << " " << download.get();
|
| + if (download.get() == NULL) {
|
| return;
|
| -
|
| - // Make history update.
|
| - DownloadItem* download = it->second;
|
| - download_history_->RemoveEntry(download);
|
| -
|
| - // Remove from our tables and delete.
|
| - history_downloads_.erase(it);
|
| - int downloads_count = downloads_.erase(download);
|
| - DCHECK_EQ(1, downloads_count);
|
| -
|
| - // Tell observers to refresh their views.
|
| + }
|
| + download_history_->RemoveEntry(download.get());
|
| + downloads_.erase(it);
|
| NotifyModelChanged();
|
| -
|
| - delete download;
|
| }
|
|
|
| -int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin,
|
| - const base::Time remove_end) {
|
| - download_history_->RemoveEntriesBetween(remove_begin, remove_end);
|
| -
|
| - // All downloads visible to the user will be in the history,
|
| - // so scan that map.
|
| - DownloadMap::iterator it = history_downloads_.begin();
|
| - std::vector<DownloadItem*> pending_deletes;
|
| - while (it != history_downloads_.end()) {
|
| - DownloadItem* download = it->second;
|
| - if (download->start_time() >= remove_begin &&
|
| - (remove_end.is_null() || download->start_time() < remove_end) &&
|
| - (download->IsComplete() ||
|
| - download->IsCancelled() ||
|
| - download->IsInterrupted())) {
|
| - AssertQueueStateConsistent(download);
|
| +void DownloadManager::GetTemporaryDownloads(
|
| + const FilePath& dir_path, ItemVector* result) {
|
| + DCHECK(result);
|
| + Search(DOWNLOAD_QUERY_FILTER(item.is_temporary()).
|
| + filenameRegex("^" + dir_path.value() + "/.*"),
|
| + result);
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << result->size();
|
| +}
|
|
|
| - // Remove from the map and move to the next in the list.
|
| - history_downloads_.erase(it++);
|
| +void DownloadManager::GetAllDownloads(
|
| + const FilePath& dir_path, ItemVector* result) {
|
| + DCHECK(result);
|
| + Search(DOWNLOAD_QUERY_FILTER(!item.is_temporary()).
|
| + filenameRegex("^" + dir_path.value() + "/.*"),
|
| + result);
|
| +}
|
|
|
| - // Also remove it from any completed dangerous downloads.
|
| - pending_deletes.push_back(download);
|
| +void DownloadManager::GetCurrentDownloads(
|
| + const FilePath& dir_path, ItemVector* result) {
|
| + DCHECK(result);
|
| + Search(DOWNLOAD_QUERY_FILTER(
|
| + !item.is_temporary() &&
|
| + (item.IsPartialDownload() ||
|
| + (item.safety_state() == DownloadItem::DANGEROUS))).
|
| + filenameRegex("^" + dir_path.value() + "/.*"),
|
| + result);
|
| +}
|
|
|
| - continue;
|
| - }
|
| +bool DownloadManager::Search(const download_util::DownloadQuery& query,
|
| + ItemVector* items,
|
| + bool merge_parent_manager,
|
| + std::string* error_msg,
|
| + ListValue* json_results) const {
|
| + ItemVector default_items;
|
| + if (items == NULL) {
|
| + items = &default_items;
|
| + }
|
| + MergeItems(merge_parent_manager, items);
|
| + return query.Search(items, error_msg, json_results);
|
| +}
|
|
|
| - ++it;
|
| +void DownloadManager::MergeItems(
|
| + bool merge_parent_manager, ItemVector* items) const {
|
| + for (DownloadMap::const_iterator it = downloads_.begin();
|
| + it != downloads_.end(); ++it) items->push_back(it->second);
|
| + if (!merge_parent_manager ||
|
| + (profile_ == NULL)) return;
|
| + Profile* original_profile = profile_->GetOriginalProfile();
|
| + if ((profile_ != NULL) &&
|
| + (original_profile != NULL) &&
|
| + (original_profile != profile_) &&
|
| + (original_profile->GetDownloadManager() != NULL)) {
|
| + original_profile->GetDownloadManager()->MergeItems(
|
| + merge_parent_manager, items);
|
| }
|
| +}
|
|
|
| - // If we aren't deleting anything, we're done.
|
| - if (pending_deletes.empty())
|
| - return 0;
|
| +void DownloadManager::SearchDownloads(const string16& query,
|
| + ItemVector* result) {
|
| + DCHECK(result);
|
| + bool otr = false;
|
| + if (profile_ != NULL) otr = profile_->IsOffTheRecord();
|
| + Search(DOWNLOAD_QUERY_FILTER1(otr,
|
| + !item.is_temporary() &&
|
| + !item.is_extension_install() &&
|
| + (item.is_otr() == otr)).
|
| + query(UTF16ToASCII(query)),
|
| + result);
|
| +}
|
|
|
| - // Remove the chosen downloads from the main owning container.
|
| - for (std::vector<DownloadItem*>::iterator it = pending_deletes.begin();
|
| - it != pending_deletes.end(); it++) {
|
| - downloads_.erase(*it);
|
| +int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin,
|
| + const base::Time remove_end) {
|
| + download_history_->RemoveEntriesBetween(remove_begin, remove_end);
|
| + ItemVector pending_deletes;
|
| + STLElementDeleter<ItemVector> delete_pending_deletes(&pending_deletes);
|
| + const base::Time unix_epoch = base::Time::UnixEpoch();
|
| + Search(DOWNLOAD_QUERY_FILTER(
|
| + item.IsComplete() ||
|
| + item.IsCancelled() ||
|
| + item.IsInterrupted()).
|
| + startedAfter((remove_begin - unix_epoch).InMilliseconds()).
|
| + startedBefore((remove_end - unix_epoch).InMilliseconds()),
|
| + &pending_deletes);
|
| + if (pending_deletes.empty()) return 0;
|
| + for (ItemVector::const_iterator iter = pending_deletes.begin();
|
| + iter != pending_deletes.end(); ++iter) {
|
| + downloads_.erase(downloads_.find((*iter)->id()));
|
| }
|
| -
|
| - // Tell observers to refresh their views.
|
| NotifyModelChanged();
|
| -
|
| - // Delete the download items themselves.
|
| int num_deleted = static_cast<int>(pending_deletes.size());
|
| -
|
| - STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
|
| - pending_deletes.clear();
|
| -
|
| return num_deleted;
|
| }
|
|
|
| @@ -989,9 +841,9 @@ void DownloadManager::SavePageAsDownloadStarted(DownloadItem* download) {
|
| #if !defined(NDEBUG)
|
| save_page_as_downloads_.insert(download);
|
| #endif
|
| - downloads_.insert(download);
|
| + downloads_[download->id()] = download;
|
| // Add to history and notify observers.
|
| - AddDownloadItemToHistory(download, DownloadHistory::kUninitializedHandle);
|
| + AddDownloadItemToHistory(download);
|
| NotifyModelChanged();
|
| }
|
|
|
| @@ -1048,36 +900,42 @@ bool DownloadManager::ShouldOpenFileBasedOnExtension(
|
| }
|
|
|
| bool DownloadManager::IsDownloadProgressKnown() {
|
| - for (DownloadMap::iterator i = in_progress_.begin();
|
| - i != in_progress_.end(); ++i) {
|
| - if (i->second->total_bytes() <= 0)
|
| + for (DownloadMap::iterator i = downloads_.begin();
|
| + i != downloads_.end(); ++i) {
|
| + if (i->second->total_bytes() <= 0) {
|
| return false;
|
| + }
|
| }
|
| -
|
| return true;
|
| }
|
|
|
| -int64 DownloadManager::GetInProgressDownloadCount() {
|
| - return in_progress_.size();
|
| +int64 DownloadManager::GetInProgressDownloadCount() const {
|
| + ItemVector in_progress;
|
| + Search(download_util::DownloadQuery().state_enum(DownloadItem::IN_PROGRESS),
|
| + &in_progress);
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << in_progress.size();
|
| + return in_progress.size();
|
| }
|
|
|
| int64 DownloadManager::GetReceivedDownloadBytes() {
|
| DCHECK(IsDownloadProgressKnown());
|
| int64 received_bytes = 0;
|
| - for (DownloadMap::iterator i = in_progress_.begin();
|
| - i != in_progress_.end(); ++i) {
|
| + for (DownloadMap::iterator i = downloads_.begin();
|
| + i != downloads_.end(); ++i) {
|
| received_bytes += i->second->received_bytes();
|
| }
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << received_bytes;
|
| return received_bytes;
|
| }
|
|
|
| int64 DownloadManager::GetTotalDownloadBytes() {
|
| DCHECK(IsDownloadProgressKnown());
|
| int64 total_bytes = 0;
|
| - for (DownloadMap::iterator i = in_progress_.begin();
|
| - i != in_progress_.end(); ++i) {
|
| + for (DownloadMap::iterator i = downloads_.begin();
|
| + i != downloads_.end(); ++i) {
|
| total_bytes += i->second->total_bytes();
|
| }
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << total_bytes;
|
| return total_bytes;
|
| }
|
|
|
| @@ -1164,56 +1022,36 @@ void DownloadManager::DangerousDownloadValidated(DownloadItem* download) {
|
| // 'DownloadHistoryInfo's in sorted order (by ascending start_time).
|
| void DownloadManager::OnQueryDownloadEntriesComplete(
|
| std::vector<DownloadHistoryInfo>* entries) {
|
| - for (size_t i = 0; i < entries->size(); ++i) {
|
| - DownloadItem* download = new DownloadItem(this, entries->at(i));
|
| - DCHECK(!ContainsKey(history_downloads_, download->db_handle()));
|
| - downloads_.insert(download);
|
| - history_downloads_[download->db_handle()] = download;
|
| - VLOG(20) << __FUNCTION__ << "()" << i << ">"
|
| - << " download = " << download->DebugString(true);
|
| + for (std::vector<DownloadHistoryInfo>::iterator it = entries->begin();
|
| + it != entries->end(); ++it) {
|
| + DownloadItem* download = new DownloadItem(this, *it);
|
| + DVLOG(2) << __PRETTY_FUNCTION__ << " " << download->id() << " " << download;
|
| + DCHECK(!ContainsKey(downloads_, download->id()));
|
| + downloads_[download->id()] = download;
|
| }
|
| NotifyModelChanged();
|
| CheckForHistoryFilesRemoval();
|
| }
|
|
|
| -void DownloadManager::AddDownloadItemToHistory(DownloadItem* download,
|
| - int64 db_handle) {
|
| +void DownloadManager::AddDownloadItemToHistory(DownloadItem* download) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - // It's not immediately obvious, but HistoryBackend::CreateDownload() can
|
| - // call this function with an invalid |db_handle|. For instance, this can
|
| - // happen when the history database is offline. We cannot have multiple
|
| - // DownloadItems with the same invalid db_handle, so we need to assign a
|
| - // unique |db_handle| here.
|
| - if (db_handle == DownloadHistory::kUninitializedHandle)
|
| - db_handle = download_history_->GetNextFakeDbHandle();
|
| -
|
| - // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/84508
|
| - // is fixed.
|
| - CHECK_NE(DownloadHistory::kUninitializedHandle, db_handle);
|
| -
|
| - DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle);
|
| - download->set_db_handle(db_handle);
|
| -
|
| - DCHECK(!ContainsKey(history_downloads_, download->db_handle()));
|
| - history_downloads_[download->db_handle()] = download;
|
| }
|
|
|
| // Once the new DownloadItem's creation info has been committed to the history
|
| // service, we associate the DownloadItem with the db handle, update our
|
| // 'history_downloads_' map and inform observers.
|
| -void DownloadManager::OnCreateDownloadEntryComplete(int32 download_id,
|
| - int64 db_handle) {
|
| +void DownloadManager::OnCreateDownloadEntryComplete(
|
| + int32 download_id) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| DownloadItem* download = GetActiveDownloadItem(download_id);
|
| - if (!download)
|
| - return;
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id << " " << download;
|
| + if (download == NULL) return;
|
| + download->SetIsInHistory(true);
|
| + VLOG(20) << __FUNCTION__ << download->DebugString(true);
|
|
|
| - VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
|
| - << " download_id = " << download_id
|
| - << " download = " << download->DebugString(true);
|
| + AddDownloadItemToHistory(download);
|
|
|
| - AddDownloadItemToHistory(download, db_handle);
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id << " " << download;
|
|
|
| // Show in the appropriate browser UI.
|
| // This includes buttons to save or cancel, for a dangerous download.
|
| @@ -1232,16 +1070,14 @@ void DownloadManager::OnCreateDownloadEntryComplete(int32 download_id,
|
| if (download->IsInProgress()) {
|
| MaybeCompleteDownload(download);
|
| } else {
|
| - DCHECK(download->IsCancelled())
|
| - << " download = " << download->DebugString(true);
|
| - in_progress_.erase(download_id);
|
| - active_downloads_.erase(download_id);
|
| download_history_->UpdateEntry(download);
|
| download->UpdateObservers();
|
| }
|
| }
|
|
|
| void DownloadManager::ShowDownloadInBrowser(DownloadItem* download) {
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download << " " << download->id();
|
| +
|
| // The 'contents' may no longer exist if the user closed the tab before we
|
| // get this start completion event. If it does, tell the origin TabContents
|
| // to display its download shelf.
|
| @@ -1276,67 +1112,29 @@ void DownloadManager::NotifyModelChanged() {
|
| }
|
|
|
| DownloadItem* DownloadManager::GetDownloadItem(int download_id) {
|
| - // The |history_downloads_| map is indexed by the download's db_handle,
|
| - // not its id, so we have to iterate.
|
| - for (DownloadMap::iterator it = history_downloads_.begin();
|
| - it != history_downloads_.end(); ++it) {
|
| - DownloadItem* item = it->second;
|
| - if (item->id() == download_id)
|
| - return item;
|
| - }
|
| - return NULL;
|
| + DownloadItem* download = downloads_[download_id];
|
| + DVLOG(1) << __PRETTY_FUNCTION__ << " " << download_id << " " << download;
|
| + return download;
|
| }
|
|
|
| DownloadItem* DownloadManager::GetActiveDownloadItem(int download_id) {
|
| - DCHECK(ContainsKey(active_downloads_, download_id));
|
| - DownloadItem* download = active_downloads_[download_id];
|
| - DCHECK(download != NULL);
|
| - return download;
|
| + return GetDownloadItem(download_id);
|
| }
|
|
|
| -// Confirm that everything in all maps is also in |downloads_|, and that
|
| -// everything in |downloads_| is also in some other map.
|
| +// Confirm that there's only one of any download_id, and that they are all > -1
|
| void DownloadManager::AssertContainersConsistent() const {
|
| -#if !defined(NDEBUG)
|
| - // Turn everything into sets.
|
| - DownloadSet active_set, history_set;
|
| - const DownloadMap* input_maps[] = {&active_downloads_, &history_downloads_};
|
| - DownloadSet* local_sets[] = {&active_set, &history_set};
|
| - DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(local_sets));
|
| - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
|
| - for (DownloadMap::const_iterator it = input_maps[i]->begin();
|
| - it != input_maps[i]->end(); it++) {
|
| - local_sets[i]->insert(&*it->second);
|
| - }
|
| + std::vector<int> ids;
|
| + for (DownloadMap::const_iterator iter = downloads_.begin();
|
| + iter != downloads_.end(); ++iter) {
|
| + ids.push_back(iter->second->id());
|
| }
|
| -
|
| - // Check if each set is fully present in downloads, and create a union.
|
| - const DownloadSet* all_sets[] = {&active_set, &history_set,
|
| - &save_page_as_downloads_};
|
| - DownloadSet downloads_union;
|
| - for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
|
| - DownloadSet remainder;
|
| - std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
|
| - std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
|
| - downloads_.begin(), downloads_.end(),
|
| - insert_it);
|
| - DCHECK(remainder.empty());
|
| - std::insert_iterator<DownloadSet>
|
| - insert_union(downloads_union, downloads_union.end());
|
| - std::set_union(downloads_union.begin(), downloads_union.end(),
|
| - all_sets[i]->begin(), all_sets[i]->end(),
|
| - insert_union);
|
| + std::sort(ids.begin(), ids.end());
|
| + int prev_id = -1;
|
| + for (std::vector<int>::const_iterator iter = ids.begin();
|
| + iter != ids.end(); ++iter) {
|
| + CHECK_GT(*iter, prev_id) << *iter << " " << prev_id;
|
| + prev_id = *iter;
|
| }
|
| -
|
| - // Is everything in downloads_ present in one of the other sets?
|
| - DownloadSet remainder;
|
| - std::insert_iterator<DownloadSet>
|
| - insert_remainder(remainder, remainder.begin());
|
| - std::set_difference(downloads_.begin(), downloads_.end(),
|
| - downloads_union.begin(), downloads_union.end(),
|
| - insert_remainder);
|
| - DCHECK(remainder.empty());
|
| -#endif
|
| }
|
|
|
| // DownloadManager::OtherDownloadManagerObserver implementation ----------------
|
|
|