| 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();
|
| }
|
|
|