Index: chrome/browser/download/download_file_manager.cc |
=================================================================== |
--- chrome/browser/download/download_file_manager.cc (revision 96793) |
+++ chrome/browser/download/download_file_manager.cc (working copy) |
@@ -1,404 +0,0 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/download/download_file_manager.h" |
- |
-#include "base/file_util.h" |
-#include "base/logging.h" |
-#include "base/stl_util.h" |
-#include "base/task.h" |
-#include "base/utf_string_conversions.h" |
-#include "chrome/browser/browser_process.h" |
-#include "chrome/browser/download/download_create_info.h" |
-#include "chrome/browser/download/download_manager.h" |
-#include "chrome/browser/download/download_request_handle.h" |
-#include "chrome/browser/download/download_util.h" |
-#include "chrome/browser/prefs/pref_service.h" |
-#include "chrome/browser/profiles/profile.h" |
-#include "chrome/browser/safe_browsing/safe_browsing_service.h" |
-#include "chrome/common/pref_names.h" |
-#include "content/browser/browser_thread.h" |
-#include "content/browser/renderer_host/resource_dispatcher_host.h" |
-#include "content/browser/tab_contents/tab_contents.h" |
-#include "googleurl/src/gurl.h" |
-#include "net/base/io_buffer.h" |
- |
-namespace { |
- |
-// Throttle updates to the UI thread so that a fast moving download doesn't |
-// cause it to become unresponsive (in milliseconds). |
-const int kUpdatePeriodMs = 500; |
- |
-} // namespace |
- |
-DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh) |
- : next_id_(0), |
- resource_dispatcher_host_(rdh) { |
-} |
- |
-DownloadFileManager::~DownloadFileManager() { |
- DCHECK(downloads_.empty()); |
-} |
- |
-void DownloadFileManager::Shutdown() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- BrowserThread::PostTask( |
- BrowserThread::FILE, FROM_HERE, |
- NewRunnableMethod(this, &DownloadFileManager::OnShutdown)); |
-} |
- |
-void DownloadFileManager::OnShutdown() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- StopUpdateTimer(); |
- STLDeleteValues(&downloads_); |
-} |
- |
-void DownloadFileManager::CreateDownloadFile(DownloadCreateInfo* info, |
- DownloadManager* download_manager, |
- bool get_hash) { |
- DCHECK(info); |
- VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- // Life of |info| ends here. No more references to it after this method. |
- scoped_ptr<DownloadCreateInfo> infop(info); |
- |
- scoped_ptr<DownloadFile> |
- download_file(new DownloadFile(info, download_manager)); |
- if (!download_file->Initialize(get_hash)) { |
- info->request_handle.CancelRequest(); |
- return; |
- } |
- |
- int32 id = info->download_id; |
- DCHECK(GetDownloadFile(id) == NULL); |
- downloads_[id] = download_file.release(); |
- |
- // The file is now ready, we can un-pause the request and start saving data. |
- info->request_handle.ResumeRequest(); |
- |
- StartUpdateTimer(); |
- |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- NewRunnableMethod(download_manager, |
- &DownloadManager::StartDownload, id)); |
-} |
- |
-DownloadFile* DownloadFileManager::GetDownloadFile(int id) { |
- DownloadFileMap::iterator it = downloads_.find(id); |
- return it == downloads_.end() ? NULL : it->second; |
-} |
- |
-void DownloadFileManager::StartUpdateTimer() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- if (!update_timer_.IsRunning()) { |
- update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), |
- this, &DownloadFileManager::UpdateInProgressDownloads); |
- } |
-} |
- |
-void DownloadFileManager::StopUpdateTimer() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- update_timer_.Stop(); |
-} |
- |
-void DownloadFileManager::UpdateInProgressDownloads() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- for (DownloadFileMap::iterator i = downloads_.begin(); |
- i != downloads_.end(); ++i) { |
- int id = i->first; |
- DownloadFile* download_file = i->second; |
- DownloadManager* manager = download_file->GetDownloadManager(); |
- if (manager) { |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- NewRunnableMethod(manager, &DownloadManager::UpdateDownload, |
- id, download_file->bytes_so_far())); |
- } |
- } |
-} |
- |
-// Called on the IO thread once the ResourceDispatcherHost has decided that a |
-// request is a download. |
-int DownloadFileManager::GetNextId() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- return next_id_++; |
-} |
- |
-void DownloadFileManager::StartDownload(DownloadCreateInfo* info) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- DCHECK(info); |
- |
- DownloadManager* manager = info->request_handle.GetDownloadManager(); |
- if (!manager) { |
- info->request_handle.CancelRequest(); |
- delete info; |
- return; |
- } |
- |
- // TODO(phajdan.jr): fix the duplication of path info below. |
- info->path = info->save_info.file_path; |
- |
- manager->CreateDownloadItem(info); |
- |
-#if defined(ENABLE_SAFE_BROWSING) |
- bool hash_needed = manager->profile()->GetPrefs()->GetBoolean( |
- prefs::kSafeBrowsingEnabled) && |
- g_browser_process->safe_browsing_service()->DownloadBinHashNeeded(); |
-#else |
- bool hash_needed = false; |
-#endif |
- |
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
- NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile, |
- info, make_scoped_refptr(manager), hash_needed)); |
-} |
- |
-// We don't forward an update to the UI thread here, since we want to throttle |
-// the UI update rate via a periodic timer. If the user has cancelled the |
-// download (in the UI thread), we may receive a few more updates before the IO |
-// thread gets the cancel message: we just delete the data since the |
-// DownloadFile has been deleted. |
-void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- std::vector<DownloadBuffer::Contents> contents; |
- { |
- base::AutoLock auto_lock(buffer->lock); |
- contents.swap(buffer->contents); |
- } |
- |
- DownloadFile* download_file = GetDownloadFile(id); |
- for (size_t i = 0; i < contents.size(); ++i) { |
- net::IOBuffer* data = contents[i].first; |
- const int data_len = contents[i].second; |
- if (download_file) |
- download_file->AppendDataToFile(data->data(), data_len); |
- data->Release(); |
- } |
-} |
- |
-void DownloadFileManager::OnResponseCompleted( |
- int id, |
- DownloadBuffer* buffer, |
- int os_error, |
- const std::string& security_info) { |
- VLOG(20) << __FUNCTION__ << "()" << " id = " << id |
- << " os_error = " << os_error |
- << " security_info = \"" << security_info << "\""; |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- delete buffer; |
- DownloadFile* download_file = GetDownloadFile(id); |
- if (!download_file) |
- return; |
- |
- download_file->Finish(); |
- |
- DownloadManager* download_manager = download_file->GetDownloadManager(); |
- if (!download_manager) { |
- CancelDownload(id); |
- return; |
- } |
- |
- std::string hash; |
- if (!download_file->GetSha256Hash(&hash)) |
- hash.clear(); |
- |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- NewRunnableMethod( |
- download_manager, &DownloadManager::OnResponseCompleted, |
- id, download_file->bytes_so_far(), os_error, hash)); |
- // We need to keep the download around until the UI thread has finalized |
- // the name. |
-} |
- |
-// This method will be sent via a user action, or shutdown on the UI thread, and |
-// run on the download thread. Since this message has been sent from the UI |
-// thread, the download may have already completed and won't exist in our map. |
-void DownloadFileManager::CancelDownload(int id) { |
- VLOG(20) << __FUNCTION__ << "()" << " id = " << id; |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- DownloadFileMap::iterator it = downloads_.find(id); |
- if (it == downloads_.end()) |
- return; |
- |
- DownloadFile* download_file = it->second; |
- VLOG(20) << __FUNCTION__ << "()" |
- << " download_file = " << download_file->DebugString(); |
- download_file->Cancel(); |
- |
- EraseDownload(id); |
-} |
- |
-void DownloadFileManager::CompleteDownload(int id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- if (!ContainsKey(downloads_, id)) |
- return; |
- |
- DownloadFile* download_file = downloads_[id]; |
- |
- VLOG(20) << " " << __FUNCTION__ << "()" |
- << " id = " << id |
- << " download_file = " << download_file->DebugString(); |
- |
- download_file->Detach(); |
- |
- EraseDownload(id); |
-} |
- |
-void DownloadFileManager::OnDownloadManagerShutdown(DownloadManager* manager) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- DCHECK(manager); |
- |
- std::set<DownloadFile*> to_remove; |
- |
- for (DownloadFileMap::iterator i = downloads_.begin(); |
- i != downloads_.end(); ++i) { |
- DownloadFile* download_file = i->second; |
- if (download_file->GetDownloadManager() == manager) { |
- download_file->CancelDownloadRequest(); |
- to_remove.insert(download_file); |
- } |
- } |
- |
- for (std::set<DownloadFile*>::iterator i = to_remove.begin(); |
- i != to_remove.end(); ++i) { |
- downloads_.erase((*i)->id()); |
- delete *i; |
- } |
-} |
- |
-// Actions from the UI thread and run on the download thread |
- |
-// The DownloadManager in the UI thread has provided an intermediate .crdownload |
-// name for the download specified by 'id'. Rename the in progress download. |
-// |
-// There are 2 possible rename cases where this method can be called: |
-// 1. tmp -> foo.crdownload (not final, safe) |
-// 2. tmp-> Unconfirmed.xxx.crdownload (not final, dangerous) |
-void DownloadFileManager::RenameInProgressDownloadFile( |
- int id, const FilePath& full_path) { |
- VLOG(20) << __FUNCTION__ << "()" << " id = " << id |
- << " full_path = \"" << full_path.value() << "\""; |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- DownloadFile* download_file = GetDownloadFile(id); |
- if (!download_file) |
- return; |
- |
- VLOG(20) << __FUNCTION__ << "()" |
- << " download_file = " << download_file->DebugString(); |
- |
- if (!download_file->Rename(full_path)) { |
- // Error. Between the time the UI thread generated 'full_path' to the time |
- // this code runs, something happened that prevents us from renaming. |
- CancelDownloadOnRename(id); |
- } |
-} |
- |
-// The DownloadManager in the UI thread has provided a final name for the |
-// download specified by 'id'. Rename the download that's in the process |
-// of completing. |
-// |
-// There are 2 possible rename cases where this method can be called: |
-// 1. foo.crdownload -> foo (final, safe) |
-// 2. Unconfirmed.xxx.crdownload -> xxx (final, validated) |
-void DownloadFileManager::RenameCompletingDownloadFile( |
- int id, const FilePath& full_path, bool overwrite_existing_file) { |
- VLOG(20) << __FUNCTION__ << "()" << " id = " << id |
- << " overwrite_existing_file = " << overwrite_existing_file |
- << " full_path = \"" << full_path.value() << "\""; |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- DownloadFile* download_file = GetDownloadFile(id); |
- if (!download_file) |
- return; |
- |
- DCHECK(download_file->GetDownloadManager()); |
- DownloadManager* download_manager = download_file->GetDownloadManager(); |
- |
- VLOG(20) << __FUNCTION__ << "()" |
- << " download_file = " << download_file->DebugString(); |
- |
- int uniquifier = 0; |
- FilePath new_path = full_path; |
- if (!overwrite_existing_file) { |
- // Make our name unique at this point, as if a dangerous file is |
- // downloading and a 2nd download is started for a file with the same |
- // name, they would have the same path. This is because we uniquify |
- // the name on download start, and at that time the first file does |
- // not exists yet, so the second file gets the same name. |
- // This should not happen in the SAFE case, and we check for that in the UI |
- // thread. |
- uniquifier = download_util::GetUniquePathNumber(new_path); |
- if (uniquifier > 0) { |
- download_util::AppendNumberToPath(&new_path, uniquifier); |
- } |
- } |
- |
- // Rename the file, overwriting if necessary. |
- if (!download_file->Rename(new_path)) { |
- // Error. Between the time the UI thread generated 'full_path' to the time |
- // this code runs, something happened that prevents us from renaming. |
- CancelDownloadOnRename(id); |
- return; |
- } |
- |
-#if defined(OS_MACOSX) |
- // Done here because we only want to do this once; see |
- // http://crbug.com/13120 for details. |
- download_file->AnnotateWithSourceInformation(); |
-#endif |
- |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- NewRunnableMethod( |
- download_manager, &DownloadManager::OnDownloadRenamedToFinalName, id, |
- new_path, uniquifier)); |
-} |
- |
-// Called only from RenameInProgressDownloadFile and |
-// RenameCompletingDownloadFile on the FILE thread. |
-void DownloadFileManager::CancelDownloadOnRename(int id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- DownloadFile* download_file = GetDownloadFile(id); |
- if (!download_file) |
- return; |
- |
- DownloadManager* download_manager = download_file->GetDownloadManager(); |
- if (!download_manager) { |
- // Without a download manager, we can't cancel the request normally, so we |
- // need to do it here. The normal path will also update the download |
- // history before cancelling the request. |
- download_file->CancelDownloadRequest(); |
- return; |
- } |
- |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- NewRunnableMethod(download_manager, |
- &DownloadManager::DownloadCancelled, id)); |
-} |
- |
-void DownloadFileManager::EraseDownload(int id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- if (!ContainsKey(downloads_, id)) |
- return; |
- |
- DownloadFile* download_file = downloads_[id]; |
- |
- VLOG(20) << " " << __FUNCTION__ << "()" |
- << " id = " << id |
- << " download_file = " << download_file->DebugString(); |
- |
- downloads_.erase(id); |
- |
- delete download_file; |
- |
- if (downloads_.empty()) |
- StopUpdateTimer(); |
-} |