Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(425)

Unified Diff: chrome/browser/download/download_manager.cc

Issue 3127008: Preliminary work on resuming downloads whose connections have expired.
Patch Set: Waiting to send download automation error message until after other downloads are canceled. Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/download/download_manager.cc
diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc
index dd350225a32c87378afe68dcc791e724dcbe8a98..4f404dd27ed4c7fbae337ada118271fb305572fe 100644
--- a/chrome/browser/download/download_manager.cc
+++ b/chrome/browser/download/download_manager.cc
@@ -75,6 +75,7 @@ void DownloadManager::Shutdown() {
// 'in_progress_' may contain DownloadItems that have not finished the start
// complete (from the history service) and thus aren't in downloads_.
+ // It may also contain DownloadItems that have been interrupted.
DownloadMap::iterator it = in_progress_.begin();
std::set<DownloadItem*> to_remove;
for (; it != in_progress_.end(); ++it) {
@@ -86,7 +87,7 @@ void DownloadManager::Shutdown() {
to_remove.insert(download);
continue;
}
- DCHECK_EQ(DownloadItem::IN_PROGRESS, download->state());
+ DCHECK(download->IsPartialDownload());
download->Cancel(false);
download_history_->UpdateEntry(download);
if (download->db_handle() == DownloadHistory::kUninitializedHandle) {
@@ -168,10 +169,12 @@ void DownloadManager::GetCurrentDownloads(
for (DownloadMap::iterator it = downloads_.begin();
it != downloads_.end(); ++it) {
if (!it->second->is_temporary() &&
- (it->second->state() == DownloadItem::IN_PROGRESS ||
- it->second->safety_state() == DownloadItem::DANGEROUS) &&
- (dir_path.empty() || it->second->full_path().DirName() == dir_path))
+ (it->second->IsPartialDownload() ||
+ (it->second->safety_state() == DownloadItem::DANGEROUS)) &&
+ (dir_path.empty() ||
+ (it->second->full_path().DirName() == dir_path))) {
result->push_back(it->second);
+ }
}
}
@@ -301,7 +304,8 @@ void DownloadManager::StartDownload(DownloadCreateInfo* info) {
// We need to move over to the download thread because we don't want to stat
// the suggested path on the UI thread.
ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
+ ChromeThread::FILE,
+ FROM_HERE,
NewRunnableMethod(
this, &DownloadManager::CheckIfSuggestedPathExists, info));
}
@@ -368,7 +372,8 @@ void DownloadManager::CheckIfSuggestedPathExists(DownloadCreateInfo* info) {
}
ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
+ ChromeThread::UI,
+ FROM_HERE,
NewRunnableMethod(this,
&DownloadManager::OnPathExistenceAvailable,
info));
@@ -411,10 +416,20 @@ void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info,
scoped_ptr<DownloadCreateInfo> infop(info);
info->path = target_path;
- DownloadItem* download = new DownloadItem(this, *info,
- profile_->IsOffTheRecord());
- DCHECK(!ContainsKey(in_progress_, info->download_id));
- in_progress_[info->download_id] = download;
+ DownloadItem* download = NULL;
+ // For partial downloads, reuse the existing DownloadItem.
+ if (info->is_partial_download && (info->download_id != -1)) {
+ DownloadMap::iterator it = in_progress_.find(info->download_id);
+ if (it != in_progress_.end()) {
+ download = it->second;
+ download->Resumed(info->request_id);
+ }
+ }
+ if (!download) {
+ download = new DownloadItem(this, *info, profile_->IsOffTheRecord());
+ DCHECK(!ContainsKey(in_progress_, info->download_id));
+ in_progress_[info->download_id] = download;
+ }
bool download_finished = ContainsKey(pending_finished_downloads_,
info->download_id);
@@ -424,7 +439,8 @@ void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info,
// We can now rename the file to its final name (or its tentative name
// in dangerous download cases).
ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
+ ChromeThread::FILE,
+ FROM_HERE,
NewRunnableMethod(
file_manager_, &DownloadFileManager::OnFinalDownloadName,
download->id(), target_path, !info->is_dangerous, this));
@@ -433,7 +449,8 @@ void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info,
// rename it to its intermediate '.crdownload' path.
FilePath download_path = download_util::GetCrDownloadPath(target_path);
ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
+ ChromeThread::FILE,
+ FROM_HERE,
NewRunnableMethod(
file_manager_, &DownloadFileManager::OnIntermediateDownloadName,
download->id(), download_path, this));
@@ -465,6 +482,17 @@ void DownloadManager::UpdateDownload(int32 download_id, int64 size) {
UpdateAppIcon();
}
+void DownloadManager::OnResponseCompleted(int32 download_id,
+ int64 size,
+ int os_error) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ if (os_error == 0) {
+ OnAllDataSaved(download_id, size);
+ } else {
+ DownloadError(download_id, size, os_error);
+ }
+}
+
void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) {
DownloadMap::iterator it = in_progress_.find(download_id);
if (it == in_progress_.end()) {
@@ -509,7 +537,8 @@ void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) {
// We first need to rename the downloaded file from its temporary name to
// its final name before we can continue.
ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
+ ChromeThread::FILE,
+ FROM_HERE,
NewRunnableMethod(
this, &DownloadManager::ProceedWithFinishedDangerousDownload,
download->db_handle(),
@@ -519,7 +548,8 @@ void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) {
if (download->need_final_rename()) {
ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
+ ChromeThread::FILE,
+ FROM_HERE,
NewRunnableMethod(
file_manager_, &DownloadFileManager::OnFinalDownloadName,
download->id(), download->full_path(), false, this));
@@ -529,6 +559,33 @@ void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) {
ContinueDownloadFinished(download);
}
+void DownloadManager::DownloadError(int32 download_id,
+ int64 size,
+ int os_error) {
+ DownloadMap::iterator it = in_progress_.find(download_id);
+ // If enough time passes, the download item could be
+ // removed from the |in_progress_| map before we get here.
+ if (it == in_progress_.end())
+ return;
+
+ DownloadItem* download = it->second;
+ download->Interrupted(size, os_error);
+
+ LOG(INFO) << "Error " << download->last_os_error() << " at offset "
+ << download->received_bytes() << " for file at \""
+ << download->url().spec() << "\"";
+
+ // Clean up will happen when the history system create callback runs if we
+ // don't have a valid db_handle yet, and otherwise when we restart.
+ if (download->db_handle() != DownloadHistory::kUninitializedHandle)
+ download_history_->UpdateEntry(download);
+
+ UpdateAppIcon();
+
+ // Notify our observers that we are interrupted.
+ download->UpdateObservers();
+}
+
void DownloadManager::DownloadRenamedToFinalName(int download_id,
const FilePath& full_path) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
@@ -580,7 +637,8 @@ void DownloadManager::ProceedWithFinishedDangerousDownload(
}
ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
+ ChromeThread::UI,
+ FROM_HERE,
NewRunnableMethod(this, &DownloadManager::DangerousDownloadRenamed,
download_handle, success, new_path, uniquifier));
}
@@ -633,14 +691,16 @@ void DownloadManager::DownloadCancelledInternal(int download_id,
int request_id) {
// Cancel the network request. RDH is guaranteed to outlive the IO thread.
ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
+ ChromeThread::IO,
+ FROM_HERE,
NewRunnableFunction(&download_util::CancelDownloadRequest,
g_browser_process->resource_dispatcher_host(),
render_process_id,
request_id));
ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
+ ChromeThread::FILE,
+ FROM_HERE,
NewRunnableMethod(
file_manager_, &DownloadFileManager::CancelDownload, download_id));
}
@@ -655,7 +715,8 @@ void DownloadManager::PauseDownload(int32 download_id, bool pause) {
return;
ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
+ ChromeThread::IO,
+ FROM_HERE,
NewRunnableMethod(this,
&DownloadManager::PauseDownloadRequest,
g_browser_process->resource_dispatcher_host(),
@@ -664,6 +725,40 @@ void DownloadManager::PauseDownload(int32 download_id, bool pause) {
pause));
}
+void DownloadManager::RestartDownload(int32 download_id) {
+ // Handle the case of clicking 'Resume' in the download shelf.
+ DownloadMap::iterator it = in_progress_.find(download_id);
+ if (it == in_progress_.end())
+ return;
+
+ DownloadItem* download = it->second;
+ if (!download->IsInterruptedDownload())
+ return;
+
+ // Restart the download.
+ // |info| is cleaned up in ResourceDispatcherHost::RestartRequestAsync().
+ DownloadCreateInfo* info = new DownloadCreateInfo(
+ download->full_path(),
+ download->url(),
+ download->start_time(),
+ download->received_bytes(),
+ download->total_bytes(),
+ DownloadItem::IN_PROGRESS, // Don't want this to show INTERRUPTED.
+ -1);
+ info->referrer_url = download->referrer_url();
+
+ // Inform the ResourceDispatcherHost that we're restarting the download.
+ ChromeThread::PostTask(
+ ChromeThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &DownloadManager::RestartDownloadRequest,
+ g_browser_process->resource_dispatcher_host(),
+ download->render_process_id(),
+ download->request_id(),
+ info));
+}
+
void DownloadManager::UpdateAppIcon() {
int64 total_bytes = 0;
int64 received_bytes = 0;
@@ -708,6 +803,14 @@ void DownloadManager::PauseDownloadRequest(ResourceDispatcherHost* rdh,
rdh->PauseRequest(render_process_id, request_id, pause);
}
+void DownloadManager::RestartDownloadRequest(ResourceDispatcherHost* rdh,
+ int render_process_id,
+ int request_id,
+ DownloadCreateInfo* info) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ rdh->RestartRequest(render_process_id, request_id, info);
+}
+
void DownloadManager::RemoveDownload(int64 download_handle) {
DownloadMap::iterator it = downloads_.find(download_handle);
if (it == downloads_.end())
@@ -805,7 +908,9 @@ void DownloadManager::DownloadUrlToFile(const GURL& url,
const DownloadSaveInfo& save_info,
TabContents* tab_contents) {
DCHECK(tab_contents);
- ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
+ ChromeThread::PostTask(
+ ChromeThread::IO,
+ FROM_HERE,
NewRunnableFunction(&download_util::DownloadUrl,
url,
referrer,
@@ -868,7 +973,8 @@ void DownloadManager::DangerousDownloadValidated(DownloadItem* download) {
return;
ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
+ ChromeThread::FILE,
+ FROM_HERE,
NewRunnableMethod(
this, &DownloadManager::ProceedWithFinishedDangerousDownload,
download->db_handle(), download->full_path(),
@@ -899,20 +1005,24 @@ void DownloadManager::OnCreateDownloadEntryComplete(DownloadCreateInfo info,
DownloadItem* download = it->second;
- // 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();
-
- DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle);
- download->set_db_handle(db_handle);
-
- // Insert into our full map.
- DCHECK(downloads_.find(download->db_handle()) == downloads_.end());
- downloads_[download->db_handle()] = download;
+ if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
+ // We're reusing the download.
+ } else {
+ // 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();
+
+ DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle);
+ download->set_db_handle(db_handle);
+
+ // Insert into our full map.
+ DCHECK(downloads_.find(download->db_handle()) == downloads_.end());
+ downloads_[download->db_handle()] = download;
+ }
// Show in the appropropriate browser UI.
ShowDownloadInBrowser(info, download);
@@ -925,7 +1035,8 @@ void DownloadManager::OnCreateDownloadEntryComplete(DownloadCreateInfo info,
// in sync with the DownloadItem's completion status, and also inform any
// observers so that they get more than just the start notification.
if (download->state() != DownloadItem::IN_PROGRESS) {
- in_progress_.erase(it);
+ if (!download->IsInterruptedDownload())
+ in_progress_.erase(it);
download_history_->UpdateEntry(download);
download->UpdateObservers();
}

Powered by Google App Engine
This is Rietveld 408576698