diff options
41 files changed, 1327 insertions, 1257 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 18b7d7b..0597f69 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -47,7 +47,7 @@ #include "chrome/browser/chrome_thread.h" #include "chrome/browser/dom_operation_notification_details.h" #include "chrome/browser/debugger/devtools_manager.h" -#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_shelf.h" #include "chrome/browser/download/save_package.h" #include "chrome/browser/extensions/crx_installer.h" diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc index a60883d..194410e 100644 --- a/chrome/browser/automation/automation_provider_observers.cc +++ b/chrome/browser/automation/automation_provider_observers.cc @@ -12,6 +12,7 @@ #include "chrome/browser/automation/automation_provider_json.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/dom_operation_notification_details.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/save_package.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_process_manager.h" diff --git a/chrome/browser/automation/automation_provider_observers.h b/chrome/browser/automation/automation_provider_observers.h index 21e87c0..08d9e08 100644 --- a/chrome/browser/automation/automation_provider_observers.h +++ b/chrome/browser/automation/automation_provider_observers.h @@ -11,6 +11,7 @@ #include "chrome/browser/bookmarks/bookmark_model_observer.h" #include "chrome/browser/browsing_data_remover.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/importer/importer.h" #include "chrome/browser/importer/importer_data_types.h" @@ -553,8 +554,8 @@ class AutomationProviderBookmarkModelObserver : BookmarkModelObserver { // When asked for pending downloads, the DownloadManager places // results in a DownloadManager::Observer. -class AutomationProviderDownloadManagerObserver : - public DownloadManager::Observer { +class AutomationProviderDownloadManagerObserver + : public DownloadManager::Observer { public: AutomationProviderDownloadManagerObserver() : DownloadManager::Observer() {} virtual ~AutomationProviderDownloadManagerObserver() {} @@ -616,8 +617,8 @@ class AutomationProviderHistoryObserver { }; // Allows the automation provider to wait for import queries to finish. -class AutomationProviderImportSettingsObserver : - public ImporterHost::Observer { +class AutomationProviderImportSettingsObserver + : public ImporterHost::Observer { public: AutomationProviderImportSettingsObserver( AutomationProvider* provider, @@ -652,8 +653,8 @@ class AutomationProviderGetPasswordsObserver : }; // Allows the automation provider to wait for clearing browser data to finish. -class AutomationProviderBrowsingDataObserver : - public BrowsingDataRemover::Observer { +class AutomationProviderBrowsingDataObserver + : public BrowsingDataRemover::Observer { public: AutomationProviderBrowsingDataObserver( AutomationProvider* provider, diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 1e30d39..364c599 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -37,6 +37,7 @@ #include "chrome/browser/debugger/devtools_window.h" #include "chrome/browser/dock_info.h" #include "chrome/browser/dom_ui/filebrowse_ui.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/download_shelf.h" diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index f84b3f3..bee3eaf 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -22,7 +22,7 @@ #include "chrome/browser/chrome_thread.h" #include "chrome/browser/debugger/debugger_wrapper.h" #include "chrome/browser/debugger/devtools_manager.h" -#include "chrome/browser/download/download_file.h" +#include "chrome/browser/download/download_file_manager.h" #include "chrome/browser/download/save_file_manager.h" #include "chrome/browser/first_run.h" #include "chrome/browser/google_url_tracker.h" diff --git a/chrome/browser/cocoa/download_item_cell.mm b/chrome/browser/cocoa/download_item_cell.mm index c9843aba..8ae9fd9 100644 --- a/chrome/browser/cocoa/download_item_cell.mm +++ b/chrome/browser/cocoa/download_item_cell.mm @@ -12,6 +12,7 @@ #import "chrome/browser/cocoa/download_item_cell.h" #import "chrome/browser/cocoa/image_utils.h" #import "chrome/browser/cocoa/themed_window.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/download_util.h" diff --git a/chrome/browser/cocoa/download_item_controller.mm b/chrome/browser/cocoa/download_item_controller.mm index 61b0aa3..00e2110 100644 --- a/chrome/browser/cocoa/download_item_controller.mm +++ b/chrome/browser/cocoa/download_item_controller.mm @@ -18,6 +18,7 @@ #import "chrome/browser/cocoa/download_shelf_controller.h" #import "chrome/browser/cocoa/themed_window.h" #import "chrome/browser/cocoa/ui_localizer.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_shelf.h" #include "chrome/browser/download/download_util.h" diff --git a/chrome/browser/cocoa/download_item_mac.h b/chrome/browser/cocoa/download_item_mac.h index a54abe4..91a8702 100644 --- a/chrome/browser/cocoa/download_item_mac.h +++ b/chrome/browser/cocoa/download_item_mac.h @@ -10,6 +10,7 @@ #include "base/scoped_nsobject.h" #include "base/scoped_ptr.h" #include "chrome/browser/cancelable_request.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/icon_manager.h" diff --git a/chrome/browser/cocoa/download_item_mac.mm b/chrome/browser/cocoa/download_item_mac.mm index 7bc3b25..b2aae2c 100644 --- a/chrome/browser/cocoa/download_item_mac.mm +++ b/chrome/browser/cocoa/download_item_mac.mm @@ -8,6 +8,7 @@ #include "chrome/browser/browser_process.h" #import "chrome/browser/cocoa/download_item_controller.h" #include "chrome/browser/cocoa/download_util_mac.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_item_model.h" #include "skia/ext/skia_utils_mac.h" diff --git a/chrome/browser/cocoa/download_shelf_controller.mm b/chrome/browser/cocoa/download_shelf_controller.mm index 53501c3..7fa1bf9 100644 --- a/chrome/browser/cocoa/download_shelf_controller.mm +++ b/chrome/browser/cocoa/download_shelf_controller.mm @@ -17,6 +17,7 @@ #include "chrome/browser/cocoa/download_shelf_mac.h" #import "chrome/browser/cocoa/download_shelf_view.h" #import "chrome/browser/cocoa/hyperlink_button_cell.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/profile.h" #include "grit/generated_resources.h" @@ -90,7 +91,7 @@ const NSTimeInterval kDownloadShelfCloseDuration = 0.12; selector:@selector(viewFrameDidChange:) name:NSViewFrameDidChangeNotification object:[self view]]; - + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); NSImage* favicon = rb.GetNSImageNamed(IDR_DOWNLOADS_FAVICON); DCHECK(favicon); diff --git a/chrome/browser/cocoa/download_util_mac.mm b/chrome/browser/cocoa/download_util_mac.mm index 75a75ec..9364520 100644 --- a/chrome/browser/cocoa/download_util_mac.mm +++ b/chrome/browser/cocoa/download_util_mac.mm @@ -8,6 +8,7 @@ #include "base/sys_string_conversions.h" #import "chrome/browser/cocoa/dock_icon.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_manager.h" #include "gfx/native_widget_types.h" #include "skia/ext/skia_utils_mac.h" diff --git a/chrome/browser/dom_ui/downloads_dom_handler.cc b/chrome/browser/dom_ui/downloads_dom_handler.cc index c637b47..126a8be 100644 --- a/chrome/browser/dom_ui/downloads_dom_handler.cc +++ b/chrome/browser/dom_ui/downloads_dom_handler.cc @@ -15,6 +15,7 @@ #include "chrome/browser/chrome_thread.h" #include "chrome/browser/dom_ui/chrome_url_data_manager.h" #include "chrome/browser/dom_ui/fileicon_source.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_util.h" #include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/profile.h" diff --git a/chrome/browser/dom_ui/downloads_dom_handler.h b/chrome/browser/dom_ui/downloads_dom_handler.h index 7eba4c2..99af1f5 100644 --- a/chrome/browser/dom_ui/downloads_dom_handler.h +++ b/chrome/browser/dom_ui/downloads_dom_handler.h @@ -8,6 +8,7 @@ #include <vector> #include "chrome/browser/dom_ui/dom_ui.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_manager.h" class Value; diff --git a/chrome/browser/download/download_file.cc b/chrome/browser/download/download_file.cc index 521a5c8..81d80b4 100644 --- a/chrome/browser/download/download_file.cc +++ b/chrome/browser/download/download_file.cc @@ -1,30 +1,15 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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.h" #include "base/file_util.h" -#include "base/path_service.h" -#include "base/stl_util-inl.h" -#include "base/task.h" -#include "base/thread.h" -#include "base/utf_string_conversions.h" #include "build/build_config.h" -#include "chrome/browser/chrome_thread.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/download_util.h" -#include "chrome/browser/net/chrome_url_request_context.h" -#include "chrome/browser/platform_util.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/renderer_host/resource_dispatcher_host.h" -#include "chrome/browser/tab_contents/tab_util.h" -#include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/common/chrome_paths.h" -#include "googleurl/src/gurl.h" -#include "net/base/io_buffer.h" -#include "net/base/net_util.h" -#include "net/url_request/url_request_context.h" +#include "chrome/browser/history/download_types.h" +#include "net/base/net_errors.h" #if defined(OS_WIN) #include "app/win_util.h" @@ -33,12 +18,6 @@ #include "chrome/browser/cocoa/file_metadata.h" #endif -// Throttle updates to the UI thread so that a fast moving download doesn't -// cause it to become unresponsive (in milliseconds). -static const int kUpdatePeriodMs = 500; - -// DownloadFile implementation ------------------------------------------------- - DownloadFile::DownloadFile(const DownloadCreateInfo* info) : file_stream_(info->save_info.file_stream), source_url_(info->url), @@ -187,477 +166,3 @@ void DownloadFile::AnnotateWithSourceInformation() { referrer_url_); #endif } - -// DownloadFileManager implementation ------------------------------------------ - -DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh) - : next_id_(0), - resource_dispatcher_host_(rdh) { -} - -DownloadFileManager::~DownloadFileManager() { - // Check for clean shutdown. - DCHECK(downloads_.empty()); - ui_progress_.clear(); -} - -// Called during the browser shutdown process to clean up any state (open files, -// timers) that live on the download_thread_. -void DownloadFileManager::Shutdown() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - StopUpdateTimer(); - ChromeThread::PostTask( - ChromeThread::FILE, FROM_HERE, - NewRunnableMethod(this, &DownloadFileManager::OnShutdown)); -} - -// Cease download thread operations. -void DownloadFileManager::OnShutdown() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - // Delete any partial downloads during shutdown. - for (DownloadFileMap::iterator it = downloads_.begin(); - it != downloads_.end(); ++it) { - DownloadFile* download = it->second; - if (download->in_progress()) - download->Cancel(); - delete download; - } - downloads_.clear(); -} - -// Initiate a request for URL to be downloaded. Called from UI thread, -// runs on IO thread. -void DownloadFileManager::OnDownloadUrl( - const GURL& url, - const GURL& referrer, - const std::string& referrer_charset, - const DownloadSaveInfo& save_info, - int render_process_host_id, - int render_view_id, - URLRequestContextGetter* request_context_getter) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - - URLRequestContext* context = request_context_getter->GetURLRequestContext(); - context->set_referrer_charset(referrer_charset); - - resource_dispatcher_host_->BeginDownload(url, - referrer, - save_info, - render_process_host_id, - render_view_id, - context); -} - -// Notifications sent from the download thread and run on the UI thread. - -// Lookup the DownloadManager for this TabContents' profile and inform it of -// a new download. -// TODO(paulg): When implementing download restart via the Downloads tab, -// there will be no 'render_process_id' or 'render_view_id'. -void DownloadFileManager::OnStartDownload(DownloadCreateInfo* info) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - DownloadManager* manager = DownloadManagerFromRenderIds(info->child_id, - info->render_view_id); - if (!manager) { - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, - resource_dispatcher_host_, - info->child_id, - info->request_id)); - delete info; - return; - } - - StartUpdateTimer(); - - // Add the download manager to our request maps for future updates. We want to - // be able to cancel all in progress downloads when a DownloadManager is - // deleted, such as when a profile is closed. We also want to be able to look - // up the DownloadManager associated with a given request without having to - // rely on using tab information, since a tab may be closed while a download - // initiated from that tab is still in progress. - DownloadRequests& downloads = requests_[manager]; - downloads.insert(info->download_id); - - // TODO(paulg): The manager will exist when restarts are implemented. - DownloadManagerMap::iterator dit = managers_.find(info->download_id); - if (dit == managers_.end()) - managers_[info->download_id] = manager; - else - NOTREACHED(); - - // StartDownload will clean up |info|. - manager->StartDownload(info); -} - -// Update the Download Manager with the finish state, and remove the request -// tracking entries. -void DownloadFileManager::OnDownloadFinished(int id, - int64 bytes_so_far) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - DownloadManager* manager = LookupManager(id); - if (manager) - manager->DownloadFinished(id, bytes_so_far); - RemoveDownload(id, manager); - RemoveDownloadFromUIProgress(id); -} - -// Lookup one in-progress download. -DownloadFile* DownloadFileManager::LookupDownload(int id) { - DownloadFileMap::iterator it = downloads_.find(id); - return it == downloads_.end() ? NULL : it->second; -} - -// The UI progress is updated on the file thread and removed on the UI thread. -void DownloadFileManager::RemoveDownloadFromUIProgress(int id) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - AutoLock lock(progress_lock_); - if (ui_progress_.find(id) != ui_progress_.end()) - ui_progress_.erase(id); -} - -// Throttle updates to the UI thread by only posting update notifications at a -// regularly controlled interval. -void DownloadFileManager::StartUpdateTimer() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - if (!update_timer_.IsRunning()) { - update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), - this, &DownloadFileManager::UpdateInProgressDownloads); - } -} - -void DownloadFileManager::StopUpdateTimer() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - update_timer_.Stop(); -} - -// Our periodic timer has fired so send the UI thread updates on all in progress -// downloads. -void DownloadFileManager::UpdateInProgressDownloads() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - AutoLock lock(progress_lock_); - ProgressMap::iterator it = ui_progress_.begin(); - for (; it != ui_progress_.end(); ++it) { - const int id = it->first; - DownloadManager* manager = LookupManager(id); - if (manager) - manager->UpdateDownload(id, it->second); - } -} - -// Called on the IO thread once the ResourceDispatcherHost has decided that a -// request is a download. -int DownloadFileManager::GetNextId() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - return next_id_++; -} - -// Notifications sent from the IO thread and run on the download thread: - -// The IO thread created 'info', but the download thread (this method) uses it -// to create a DownloadFile, then passes 'info' to the UI thread where it is -// finally consumed and deleted. -void DownloadFileManager::StartDownload(DownloadCreateInfo* info) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - DCHECK(info); - - DownloadFile* download = new DownloadFile(info); - if (!download->Initialize()) { - // Couldn't open, cancel the operation. The UI thread does not yet know - // about this download so we have to clean up 'info'. We need to get back - // to the IO thread to cancel the network request and CancelDownloadRequest - // on the UI thread is the safe way to do that. - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, - resource_dispatcher_host_, - info->child_id, - info->request_id)); - delete info; - delete download; - return; - } - - DCHECK(LookupDownload(info->download_id) == NULL); - downloads_[info->download_id] = download; - info->path = download->full_path(); - { - AutoLock lock(progress_lock_); - ui_progress_[info->download_id] = info->received_bytes; - } - - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - NewRunnableMethod(this, &DownloadFileManager::OnStartDownload, info)); -} - -// 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(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - std::vector<DownloadBuffer::Contents> contents; - { - AutoLock auto_lock(buffer->lock); - contents.swap(buffer->contents); - } - - DownloadFile* download = LookupDownload(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) - download->AppendDataToFile(data->data(), data_len); - data->Release(); - } - - if (download) { - AutoLock lock(progress_lock_); - ui_progress_[download->id()] = download->bytes_so_far(); - } -} - -void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - delete buffer; - DownloadFileMap::iterator it = downloads_.find(id); - if (it != downloads_.end()) { - DownloadFile* download = it->second; - download->set_in_progress(false); - - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - NewRunnableMethod( - this, &DownloadFileManager::OnDownloadFinished, - id, download->bytes_so_far())); - - // We need to keep the download around until the UI thread has finalized - // the name. - if (download->path_renamed()) { - downloads_.erase(it); - delete download; - } - } - - if (downloads_.empty()) - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); -} - -// 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) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - DownloadFileMap::iterator it = downloads_.find(id); - if (it != downloads_.end()) { - DownloadFile* download = it->second; - download->set_in_progress(false); - - download->Cancel(); - - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - NewRunnableMethod( - this, &DownloadFileManager::RemoveDownloadFromUIProgress, - download->id())); - - if (download->path_renamed()) { - downloads_.erase(it); - delete download; - } - } - - if (downloads_.empty()) { - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); - } -} - -void DownloadFileManager::DownloadUrl( - const GURL& url, - const GURL& referrer, - const std::string& referrer_charset, - const DownloadSaveInfo& save_info, - int render_process_host_id, - int render_view_id, - URLRequestContextGetter* request_context_getter) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod(this, - &DownloadFileManager::OnDownloadUrl, - url, - referrer, - referrer_charset, - save_info, - render_process_host_id, - render_view_id, - request_context_getter)); -} - -// Relate a download ID to its owning DownloadManager. -DownloadManager* DownloadFileManager::LookupManager(int download_id) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - DownloadManagerMap::iterator it = managers_.find(download_id); - if (it != managers_.end()) - return it->second; - return NULL; -} - -// Utility function for look up table maintenance, called on the UI thread. -// A manager may have multiple downloads in progress, so we just look up the -// one download (id) and remove it from the set, and remove the set if it -// becomes empty. -void DownloadFileManager::RemoveDownload(int id, DownloadManager* manager) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - if (manager) { - RequestMap::iterator it = requests_.find(manager); - if (it != requests_.end()) { - DownloadRequests& downloads = it->second; - DownloadRequests::iterator rit = downloads.find(id); - if (rit != downloads.end()) - downloads.erase(rit); - if (downloads.empty()) - requests_.erase(it); - } - } - - // A download can only have one manager, so remove it if it exists. - DownloadManagerMap::iterator dit = managers_.find(id); - if (dit != managers_.end()) - managers_.erase(dit); -} - -// Utility function for converting request IDs to a TabContents. Must be called -// only on the UI thread since Profile operations may create UI objects, such as -// the first call to profile->GetDownloadManager(). -// static -DownloadManager* DownloadFileManager::DownloadManagerFromRenderIds( - int render_process_id, int render_view_id) { - TabContents* contents = tab_util::GetTabContentsByID(render_process_id, - render_view_id); - if (contents) { - Profile* profile = contents->profile(); - if (profile) - return profile->GetDownloadManager(); - } - - return NULL; -} - -// Called by DownloadManagers in their destructor, and only on the UI thread. -void DownloadFileManager::RemoveDownloadManager(DownloadManager* manager) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - DCHECK(manager); - RequestMap::iterator it = requests_.find(manager); - if (it == requests_.end()) - return; - - const DownloadRequests& requests = it->second; - DownloadRequests::const_iterator i = requests.begin(); - for (; i != requests.end(); ++i) { - DownloadManagerMap::iterator dit = managers_.find(*i); - if (dit != managers_.end()) { - DCHECK(dit->second == manager); - managers_.erase(dit); - } - } - - requests_.erase(it); -} - -// Actions from the UI thread and run on the download thread - -// Open a download, or show it in a file explorer window. We run on this -// thread to avoid blocking the UI with (potentially) slow Shell operations. -// TODO(paulg): File 'stat' operations. -#if !defined(OS_MACOSX) -void DownloadFileManager::OnShowDownloadInShell(const FilePath& full_path) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - platform_util::ShowItemInFolder(full_path); -} -#endif - -// Launches the selected download using ShellExecute 'open' verb. For windows, -// if there is a valid parent window, the 'safer' version will be used which can -// display a modal dialog asking for user consent on dangerous files. -#if !defined(OS_MACOSX) -void DownloadFileManager::OnOpenDownloadInShell(const FilePath& full_path, - const GURL& url, - gfx::NativeView parent_window) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); -#if defined(OS_WIN) - if (NULL != parent_window) { - win_util::SaferOpenItemViaShell(parent_window, L"", full_path, - UTF8ToWide(url.spec())); - return; - } -#endif - platform_util::OpenItem(full_path); -} -#endif // OS_MACOSX - -// The DownloadManager in the UI thread has provided a final name for the -// download specified by 'id'. Rename the in progress download, and remove it -// from our table if it has been completed or cancelled already. -void DownloadFileManager::OnFinalDownloadName(int id, - const FilePath& full_path, - DownloadManager* manager) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - DownloadFileMap::iterator it = downloads_.find(id); - if (it == downloads_.end()) - return; - - file_util::CreateDirectory(full_path.DirName()); - - DownloadFile* download = it->second; - if (download->Rename(full_path)) { -#if defined(OS_MACOSX) - // Done here because we only want to do this once; see - // http://crbug.com/13120 for details. - download->AnnotateWithSourceInformation(); -#endif - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - NewRunnableMethod( - manager, &DownloadManager::DownloadRenamedToFinalName, id, - full_path)); - } else { - // Error. Between the time the UI thread generated 'full_path' to the time - // this code runs, something happened that prevents us from renaming. - DownloadManagerMap::iterator dmit = managers_.find(download->id()); - if (dmit != managers_.end()) { - DownloadManager* dlm = dmit->second; - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - NewRunnableMethod(dlm, &DownloadManager::DownloadCancelled, id)); - } else { - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, - resource_dispatcher_host_, - download->child_id(), - download->request_id())); - } - } - - // If the download has completed before we got this final name, we remove it - // from our in progress map. - if (!download->in_progress()) { - downloads_.erase(it); - delete download; - } - - if (downloads_.empty()) { - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); - } -} - diff --git a/chrome/browser/download/download_file.h b/chrome/browser/download/download_file.h index b905d83..97057a6 100644 --- a/chrome/browser/download/download_file.h +++ b/chrome/browser/download/download_file.h @@ -1,42 +1,6 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. -// -// Objects that handle file operations for downloads, on the download thread. -// -// The DownloadFileManager owns a set of DownloadFile objects, each of which -// represent one in progress download and performs the disk IO for that -// download. The DownloadFileManager itself is a singleton object owned by the -// ResourceDispatcherHost. -// -// The DownloadFileManager uses the file_thread for performing file write -// operations, in order to avoid disk activity on either the IO (network) thread -// and the UI thread. It coordinates the notifications from the network and UI. -// -// A typical download operation involves multiple threads: -// -// Updating an in progress download -// io_thread -// |----> data ---->| -// file_thread (writes to disk) -// |----> stats ---->| -// ui_thread (feedback for user and -// updates to history) -// -// Cancel operations perform the inverse order when triggered by a user action: -// ui_thread (user click) -// |----> cancel command ---->| -// file_thread (close file) -// |----> cancel command ---->| -// io_thread (stops net IO -// for download) -// -// The DownloadFileManager tracks download requests, mapping from a download -// ID (unique integer created in the IO thread) to the DownloadManager for the -// tab (profile) where the download was initiated. In the event of a tab closure -// during a download, the DownloadFileManager will continue to route data to the -// appropriate DownloadManager. In progress downloads are cancelled for a -// DownloadManager that exits (such as when closing a profile). #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_H_ #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_H_ @@ -49,48 +13,11 @@ #include "base/file_path.h" #include "base/hash_tables.h" #include "base/linked_ptr.h" -#include "base/lock.h" -#include "base/ref_counted.h" -#include "base/timer.h" +#include "chrome/browser/download/download_types.h" #include "chrome/browser/power_save_blocker.h" -#include "gfx/native_widget_types.h" #include "googleurl/src/gurl.h" -#include "net/base/file_stream.h" -namespace net { -class IOBuffer; -} struct DownloadCreateInfo; -class DownloadManager; -class ResourceDispatcherHost; -class URLRequestContextGetter; - -// DownloadBuffer -------------------------------------------------------------- - -// This container is created and populated on the io_thread, and passed to the -// file_thread for writing. In order to avoid flooding the file_thread with too -// many small write messages, each write is appended to the DownloadBuffer while -// waiting for the task to run on the file_thread. Access to the write buffers -// is synchronized via the lock. Each entry in 'contents' represents one data -// buffer and its size in bytes. - -struct DownloadBuffer { - Lock lock; - typedef std::pair<net::IOBuffer*, int> Contents; - std::vector<Contents> contents; -}; - -// DownloadSaveInfo ------------------------------------------------------------ - -// Holds the information about how to save a download file. -struct DownloadSaveInfo { - FilePath file_path; - linked_ptr<net::FileStream> file_stream; - - DownloadSaveInfo() { } -}; - -// DownloadFile ---------------------------------------------------------------- // These objects live exclusively on the download thread and handle the writing // operations for one download. These objects live only for the duration that @@ -175,128 +102,4 @@ class DownloadFile { DISALLOW_COPY_AND_ASSIGN(DownloadFile); }; - -// DownloadFileManager --------------------------------------------------------- - -// Manages all in progress downloads. -class DownloadFileManager - : public base::RefCountedThreadSafe<DownloadFileManager> { - public: - explicit DownloadFileManager(ResourceDispatcherHost* rdh); - - // Called on shutdown on the UI thread. - void Shutdown(); - - // Called on the IO thread - int GetNextId(); - - // Handlers for notifications sent from the IO thread and run on the - // download thread. - void StartDownload(DownloadCreateInfo* info); - void UpdateDownload(int id, DownloadBuffer* buffer); - void CancelDownload(int id); - void DownloadFinished(int id, DownloadBuffer* buffer); - - // Download the URL. Called on the UI thread and forwarded to the - // ResourceDispatcherHost on the IO thread. - void DownloadUrl(const GURL& url, - const GURL& referrer, - const std::string& referrer_charset, - const DownloadSaveInfo& save_info, - int render_process_host_id, - int render_view_id, - URLRequestContextGetter* request_context_getter); - - // Called on the UI thread to remove a download item or manager. - void RemoveDownloadManager(DownloadManager* manager); - void RemoveDownload(int id, DownloadManager* manager); - -#if !defined(OS_MACOSX) - // The open and show methods run on the file thread, which does not work on - // Mac OS X (which uses the UI thread for opens). - - // Handler for shell operations sent from the UI to the download thread. - void OnShowDownloadInShell(const FilePath& full_path); - - // Handler to open or execute a downloaded file. - void OnOpenDownloadInShell(const FilePath& full_path, - const GURL& url, - gfx::NativeView parent_window); -#endif - - // The download manager has provided a final name for a download. Sent from - // the UI thread and run on the download thread. - void OnFinalDownloadName(int id, const FilePath& full_path, - DownloadManager* download_manager); - - private: - friend class base::RefCountedThreadSafe<DownloadFileManager>; - - ~DownloadFileManager(); - - // Timer helpers for updating the UI about the current progress of a download. - void StartUpdateTimer(); - void StopUpdateTimer(); - void UpdateInProgressDownloads(); - - // Clean up helper that runs on the download thread. - void OnShutdown(); - - // Run on the IO thread to initiate the download of a URL. - void OnDownloadUrl(const GURL& url, - const GURL& referrer, - const std::string& referrer_charset, - const DownloadSaveInfo& save_info, - int render_process_host_id, - int render_view_id, - URLRequestContextGetter* request_context_getter); - - // Handlers for notifications sent from the download thread and run on - // the UI thread. - void OnStartDownload(DownloadCreateInfo* info); - void OnDownloadFinished(int id, int64 bytes_so_far); - - // Called only on UI thread to get the DownloadManager for a tab's profile. - static DownloadManager* DownloadManagerFromRenderIds(int render_process_id, - int review_view_id); - DownloadManager* LookupManager(int download_id); - - // Called only on the download thread. - DownloadFile* LookupDownload(int id); - - // Called on the UI thread to remove a download from the UI progress table. - void RemoveDownloadFromUIProgress(int id); - - // Unique ID for each DownloadFile. - int next_id_; - - // A map of all in progress downloads. - typedef base::hash_map<int, DownloadFile*> DownloadFileMap; - DownloadFileMap downloads_; - - // Throttle updates to the UI thread. - base::RepeatingTimer<DownloadFileManager> update_timer_; - - ResourceDispatcherHost* resource_dispatcher_host_; - - // Tracking which DownloadManager to send data to, called only on UI thread. - // DownloadManagerMap maps download IDs to their DownloadManager. - typedef base::hash_map<int, DownloadManager*> DownloadManagerMap; - DownloadManagerMap managers_; - - // RequestMap maps a DownloadManager to all in-progress download IDs. - // Called only on the UI thread. - typedef base::hash_set<int> DownloadRequests; - typedef std::map<DownloadManager*, DownloadRequests> RequestMap; - RequestMap requests_; - - // Used for progress updates on the UI thread, mapping download->id() to bytes - // received so far. Written to by the file thread and read by the UI thread. - typedef base::hash_map<int, int64> ProgressMap; - ProgressMap ui_progress_; - Lock progress_lock_; - - DISALLOW_COPY_AND_ASSIGN(DownloadFileManager); -}; - #endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_H_ diff --git a/chrome/browser/download/download_file_manager.cc b/chrome/browser/download/download_file_manager.cc new file mode 100644 index 0000000..90a95f4 --- /dev/null +++ b/chrome/browser/download/download_file_manager.cc @@ -0,0 +1,507 @@ +// Copyright (c) 2010 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/task.h" +#include "base/utf_string_conversions.h" +#include "build/build_config.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/history/download_types.h" +#include "chrome/browser/net/chrome_url_request_context.h" +#include "chrome/browser/platform_util.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/renderer_host/resource_dispatcher_host.h" +#include "chrome/browser/tab_contents/tab_util.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "googleurl/src/gurl.h" + +#if defined(OS_WIN) +#include "app/win_util.h" +#include "chrome/common/win_safe_util.h" +#elif defined(OS_MACOSX) +#include "chrome/browser/cocoa/file_metadata.h" +#endif + +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() { + // Check for clean shutdown. + DCHECK(downloads_.empty()); + ui_progress_.clear(); +} + +// Called during the browser shutdown process to clean up any state (open files, +// timers) that live on the download_thread_. +void DownloadFileManager::Shutdown() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + StopUpdateTimer(); + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, &DownloadFileManager::OnShutdown)); +} + +// Cease download thread operations. +void DownloadFileManager::OnShutdown() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + // Delete any partial downloads during shutdown. + for (DownloadFileMap::iterator it = downloads_.begin(); + it != downloads_.end(); ++it) { + DownloadFile* download = it->second; + if (download->in_progress()) + download->Cancel(); + delete download; + } + downloads_.clear(); +} + +// Initiate a request for URL to be downloaded. Called from UI thread, +// runs on IO thread. +void DownloadFileManager::OnDownloadUrl( + const GURL& url, + const GURL& referrer, + const std::string& referrer_charset, + const DownloadSaveInfo& save_info, + int render_process_host_id, + int render_view_id, + URLRequestContextGetter* request_context_getter) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + + URLRequestContext* context = request_context_getter->GetURLRequestContext(); + context->set_referrer_charset(referrer_charset); + + resource_dispatcher_host_->BeginDownload(url, + referrer, + save_info, + render_process_host_id, + render_view_id, + context); +} + +// Notifications sent from the download thread and run on the UI thread. + +// Lookup the DownloadManager for this TabContents' profile and inform it of +// a new download. +// TODO(paulg): When implementing download restart via the Downloads tab, +// there will be no 'render_process_id' or 'render_view_id'. +void DownloadFileManager::OnStartDownload(DownloadCreateInfo* info) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + DownloadManager* manager = DownloadManagerFromRenderIds(info->child_id, + info->render_view_id); + if (!manager) { + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, + resource_dispatcher_host_, + info->child_id, + info->request_id)); + delete info; + return; + } + + StartUpdateTimer(); + + // Add the download manager to our request maps for future updates. We want to + // be able to cancel all in progress downloads when a DownloadManager is + // deleted, such as when a profile is closed. We also want to be able to look + // up the DownloadManager associated with a given request without having to + // rely on using tab information, since a tab may be closed while a download + // initiated from that tab is still in progress. + DownloadRequests& downloads = requests_[manager]; + downloads.insert(info->download_id); + + // TODO(paulg): The manager will exist when restarts are implemented. + DownloadManagerMap::iterator dit = managers_.find(info->download_id); + if (dit == managers_.end()) + managers_[info->download_id] = manager; + else + NOTREACHED(); + + // StartDownload will clean up |info|. + manager->StartDownload(info); +} + +// Update the Download Manager with the finish state, and remove the request +// tracking entries. +void DownloadFileManager::OnDownloadFinished(int id, + int64 bytes_so_far) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + DownloadManager* manager = LookupManager(id); + if (manager) + manager->DownloadFinished(id, bytes_so_far); + RemoveDownload(id, manager); + RemoveDownloadFromUIProgress(id); +} + +// Lookup one in-progress download. +DownloadFile* DownloadFileManager::LookupDownload(int id) { + DownloadFileMap::iterator it = downloads_.find(id); + return it == downloads_.end() ? NULL : it->second; +} + +// The UI progress is updated on the file thread and removed on the UI thread. +void DownloadFileManager::RemoveDownloadFromUIProgress(int id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + AutoLock lock(progress_lock_); + if (ui_progress_.find(id) != ui_progress_.end()) + ui_progress_.erase(id); +} + +// Throttle updates to the UI thread by only posting update notifications at a +// regularly controlled interval. +void DownloadFileManager::StartUpdateTimer() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + if (!update_timer_.IsRunning()) { + update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), + this, &DownloadFileManager::UpdateInProgressDownloads); + } +} + +void DownloadFileManager::StopUpdateTimer() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + update_timer_.Stop(); +} + +// Our periodic timer has fired so send the UI thread updates on all in progress +// downloads. +void DownloadFileManager::UpdateInProgressDownloads() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + AutoLock lock(progress_lock_); + ProgressMap::iterator it = ui_progress_.begin(); + for (; it != ui_progress_.end(); ++it) { + const int id = it->first; + DownloadManager* manager = LookupManager(id); + if (manager) + manager->UpdateDownload(id, it->second); + } +} + +// Called on the IO thread once the ResourceDispatcherHost has decided that a +// request is a download. +int DownloadFileManager::GetNextId() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + return next_id_++; +} + +// Notifications sent from the IO thread and run on the download thread: + +// The IO thread created 'info', but the download thread (this method) uses it +// to create a DownloadFile, then passes 'info' to the UI thread where it is +// finally consumed and deleted. +void DownloadFileManager::StartDownload(DownloadCreateInfo* info) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + DCHECK(info); + + DownloadFile* download = new DownloadFile(info); + if (!download->Initialize()) { + // Couldn't open, cancel the operation. The UI thread does not yet know + // about this download so we have to clean up 'info'. We need to get back + // to the IO thread to cancel the network request and CancelDownloadRequest + // on the UI thread is the safe way to do that. + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, + resource_dispatcher_host_, + info->child_id, + info->request_id)); + delete info; + delete download; + return; + } + + DCHECK(LookupDownload(info->download_id) == NULL); + downloads_[info->download_id] = download; + info->path = download->full_path(); + { + AutoLock lock(progress_lock_); + ui_progress_[info->download_id] = info->received_bytes; + } + + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &DownloadFileManager::OnStartDownload, info)); +} + +// 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(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + std::vector<DownloadBuffer::Contents> contents; + { + AutoLock auto_lock(buffer->lock); + contents.swap(buffer->contents); + } + + DownloadFile* download = LookupDownload(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) + download->AppendDataToFile(data->data(), data_len); + data->Release(); + } + + if (download) { + AutoLock lock(progress_lock_); + ui_progress_[download->id()] = download->bytes_so_far(); + } +} + +void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + delete buffer; + DownloadFileMap::iterator it = downloads_.find(id); + if (it != downloads_.end()) { + DownloadFile* download = it->second; + download->set_in_progress(false); + + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod( + this, &DownloadFileManager::OnDownloadFinished, + id, download->bytes_so_far())); + + // We need to keep the download around until the UI thread has finalized + // the name. + if (download->path_renamed()) { + downloads_.erase(it); + delete download; + } + } + + if (downloads_.empty()) + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); +} + +// 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) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + DownloadFileMap::iterator it = downloads_.find(id); + if (it != downloads_.end()) { + DownloadFile* download = it->second; + download->set_in_progress(false); + + download->Cancel(); + + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod( + this, &DownloadFileManager::RemoveDownloadFromUIProgress, + download->id())); + + if (download->path_renamed()) { + downloads_.erase(it); + delete download; + } + } + + if (downloads_.empty()) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); + } +} + +void DownloadFileManager::DownloadUrl( + const GURL& url, + const GURL& referrer, + const std::string& referrer_charset, + const DownloadSaveInfo& save_info, + int render_process_host_id, + int render_view_id, + URLRequestContextGetter* request_context_getter) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, + &DownloadFileManager::OnDownloadUrl, + url, + referrer, + referrer_charset, + save_info, + render_process_host_id, + render_view_id, + request_context_getter)); +} + +// Relate a download ID to its owning DownloadManager. +DownloadManager* DownloadFileManager::LookupManager(int download_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + DownloadManagerMap::iterator it = managers_.find(download_id); + if (it != managers_.end()) + return it->second; + return NULL; +} + +// Utility function for look up table maintenance, called on the UI thread. +// A manager may have multiple downloads in progress, so we just look up the +// one download (id) and remove it from the set, and remove the set if it +// becomes empty. +void DownloadFileManager::RemoveDownload(int id, DownloadManager* manager) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + if (manager) { + RequestMap::iterator it = requests_.find(manager); + if (it != requests_.end()) { + DownloadRequests& downloads = it->second; + DownloadRequests::iterator rit = downloads.find(id); + if (rit != downloads.end()) + downloads.erase(rit); + if (downloads.empty()) + requests_.erase(it); + } + } + + // A download can only have one manager, so remove it if it exists. + DownloadManagerMap::iterator dit = managers_.find(id); + if (dit != managers_.end()) + managers_.erase(dit); +} + +// Utility function for converting request IDs to a TabContents. Must be called +// only on the UI thread since Profile operations may create UI objects, such as +// the first call to profile->GetDownloadManager(). +// static +DownloadManager* DownloadFileManager::DownloadManagerFromRenderIds( + int render_process_id, int render_view_id) { + TabContents* contents = tab_util::GetTabContentsByID(render_process_id, + render_view_id); + if (contents) { + Profile* profile = contents->profile(); + if (profile) + return profile->GetDownloadManager(); + } + + return NULL; +} + +// Called by DownloadManagers in their destructor, and only on the UI thread. +void DownloadFileManager::RemoveDownloadManager(DownloadManager* manager) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + DCHECK(manager); + RequestMap::iterator it = requests_.find(manager); + if (it == requests_.end()) + return; + + const DownloadRequests& requests = it->second; + DownloadRequests::const_iterator i = requests.begin(); + for (; i != requests.end(); ++i) { + DownloadManagerMap::iterator dit = managers_.find(*i); + if (dit != managers_.end()) { + DCHECK(dit->second == manager); + managers_.erase(dit); + } + } + + requests_.erase(it); +} + +// Actions from the UI thread and run on the download thread + +// Open a download, or show it in a file explorer window. We run on this +// thread to avoid blocking the UI with (potentially) slow Shell operations. +// TODO(paulg): File 'stat' operations. +#if !defined(OS_MACOSX) +void DownloadFileManager::OnShowDownloadInShell(const FilePath& full_path) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + platform_util::ShowItemInFolder(full_path); +} +#endif + +// Launches the selected download using ShellExecute 'open' verb. For windows, +// if there is a valid parent window, the 'safer' version will be used which can +// display a modal dialog asking for user consent on dangerous files. +#if !defined(OS_MACOSX) +void DownloadFileManager::OnOpenDownloadInShell(const FilePath& full_path, + const GURL& url, + gfx::NativeView parent_window) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); +#if defined(OS_WIN) + if (NULL != parent_window) { + win_util::SaferOpenItemViaShell(parent_window, L"", full_path, + UTF8ToWide(url.spec())); + return; + } +#endif + platform_util::OpenItem(full_path); +} +#endif // OS_MACOSX + +// The DownloadManager in the UI thread has provided a final name for the +// download specified by 'id'. Rename the in progress download, and remove it +// from our table if it has been completed or cancelled already. +void DownloadFileManager::OnFinalDownloadName(int id, + const FilePath& full_path, + DownloadManager* manager) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + DownloadFileMap::iterator it = downloads_.find(id); + if (it == downloads_.end()) + return; + + file_util::CreateDirectory(full_path.DirName()); + + DownloadFile* download = it->second; + if (download->Rename(full_path)) { +#if defined(OS_MACOSX) + // Done here because we only want to do this once; see + // http://crbug.com/13120 for details. + download->AnnotateWithSourceInformation(); +#endif + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod( + manager, &DownloadManager::DownloadRenamedToFinalName, id, + full_path)); + } else { + // Error. Between the time the UI thread generated 'full_path' to the time + // this code runs, something happened that prevents us from renaming. + DownloadManagerMap::iterator dmit = managers_.find(download->id()); + if (dmit != managers_.end()) { + DownloadManager* dlm = dmit->second; + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(dlm, &DownloadManager::DownloadCancelled, id)); + } else { + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, + resource_dispatcher_host_, + download->child_id(), + download->request_id())); + } + } + + // If the download has completed before we got this final name, we remove it + // from our in progress map. + if (!download->in_progress()) { + downloads_.erase(it); + delete download; + } + + if (downloads_.empty()) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); + } +} + diff --git a/chrome/browser/download/download_file_manager.h b/chrome/browser/download/download_file_manager.h new file mode 100644 index 0000000..f4c1a5e --- /dev/null +++ b/chrome/browser/download/download_file_manager.h @@ -0,0 +1,183 @@ +// Copyright (c) 2010 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. +// +// The DownloadFileManager owns a set of DownloadFile objects, each of which +// represent one in progress download and performs the disk IO for that +// download. The DownloadFileManager itself is a singleton object owned by the +// ResourceDispatcherHost. +// +// The DownloadFileManager uses the file_thread for performing file write +// operations, in order to avoid disk activity on either the IO (network) thread +// and the UI thread. It coordinates the notifications from the network and UI. +// +// A typical download operation involves multiple threads: +// +// Updating an in progress download +// io_thread +// |----> data ---->| +// file_thread (writes to disk) +// |----> stats ---->| +// ui_thread (feedback for user and +// updates to history) +// +// Cancel operations perform the inverse order when triggered by a user action: +// ui_thread (user click) +// |----> cancel command ---->| +// file_thread (close file) +// |----> cancel command ---->| +// io_thread (stops net IO +// for download) +// +// The DownloadFileManager tracks download requests, mapping from a download +// ID (unique integer created in the IO thread) to the DownloadManager for the +// tab (profile) where the download was initiated. In the event of a tab closure +// during a download, the DownloadFileManager will continue to route data to the +// appropriate DownloadManager. In progress downloads are cancelled for a +// DownloadManager that exits (such as when closing a profile). + +#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_MANAGER_H_ +#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_MANAGER_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/hash_tables.h" +#include "base/lock.h" +#include "base/ref_counted.h" +#include "base/timer.h" +#include "gfx/native_widget_types.h" + +struct DownloadBuffer; +struct DownloadCreateInfo; +struct DownloadSaveInfo; +class DownloadFile; +class DownloadManager; +class FilePath; +class GURL; +class ResourceDispatcherHost; +class URLRequestContextGetter; + +// Manages all in progress downloads. +class DownloadFileManager + : public base::RefCountedThreadSafe<DownloadFileManager> { + public: + explicit DownloadFileManager(ResourceDispatcherHost* rdh); + + // Called on shutdown on the UI thread. + void Shutdown(); + + // Called on the IO thread + int GetNextId(); + + // Handlers for notifications sent from the IO thread and run on the + // download thread. + void StartDownload(DownloadCreateInfo* info); + void UpdateDownload(int id, DownloadBuffer* buffer); + void CancelDownload(int id); + void DownloadFinished(int id, DownloadBuffer* buffer); + + // Download the URL. Called on the UI thread and forwarded to the + // ResourceDispatcherHost on the IO thread. + void DownloadUrl(const GURL& url, + const GURL& referrer, + const std::string& referrer_charset, + const DownloadSaveInfo& save_info, + int render_process_host_id, + int render_view_id, + URLRequestContextGetter* request_context_getter); + + // Called on the UI thread to remove a download item or manager. + void RemoveDownloadManager(DownloadManager* manager); + void RemoveDownload(int id, DownloadManager* manager); + +#if !defined(OS_MACOSX) + // The open and show methods run on the file thread, which does not work on + // Mac OS X (which uses the UI thread for opens). + + // Handler for shell operations sent from the UI to the download thread. + void OnShowDownloadInShell(const FilePath& full_path); + + // Handler to open or execute a downloaded file. + void OnOpenDownloadInShell(const FilePath& full_path, + const GURL& url, + gfx::NativeView parent_window); +#endif + + // The download manager has provided a final name for a download. Sent from + // the UI thread and run on the download thread. + void OnFinalDownloadName(int id, const FilePath& full_path, + DownloadManager* download_manager); + + private: + friend class base::RefCountedThreadSafe<DownloadFileManager>; + + ~DownloadFileManager(); + + // Timer helpers for updating the UI about the current progress of a download. + void StartUpdateTimer(); + void StopUpdateTimer(); + void UpdateInProgressDownloads(); + + // Clean up helper that runs on the download thread. + void OnShutdown(); + + // Run on the IO thread to initiate the download of a URL. + void OnDownloadUrl(const GURL& url, + const GURL& referrer, + const std::string& referrer_charset, + const DownloadSaveInfo& save_info, + int render_process_host_id, + int render_view_id, + URLRequestContextGetter* request_context_getter); + + // Handlers for notifications sent from the download thread and run on + // the UI thread. + void OnStartDownload(DownloadCreateInfo* info); + void OnDownloadFinished(int id, int64 bytes_so_far); + + // Called only on UI thread to get the DownloadManager for a tab's profile. + static DownloadManager* DownloadManagerFromRenderIds(int render_process_id, + int review_view_id); + DownloadManager* LookupManager(int download_id); + + // Called only on the download thread. + DownloadFile* LookupDownload(int id); + + // Called on the UI thread to remove a download from the UI progress table. + void RemoveDownloadFromUIProgress(int id); + + // Unique ID for each DownloadFile. + int next_id_; + + // A map of all in progress downloads. + typedef base::hash_map<int, DownloadFile*> DownloadFileMap; + DownloadFileMap downloads_; + + // Throttle updates to the UI thread. + base::RepeatingTimer<DownloadFileManager> update_timer_; + + ResourceDispatcherHost* resource_dispatcher_host_; + + // Tracking which DownloadManager to send data to, called only on UI thread. + // DownloadManagerMap maps download IDs to their DownloadManager. + typedef base::hash_map<int, DownloadManager*> DownloadManagerMap; + DownloadManagerMap managers_; + + // RequestMap maps a DownloadManager to all in-progress download IDs. + // Called only on the UI thread. + typedef base::hash_set<int> DownloadRequests; + typedef std::map<DownloadManager*, DownloadRequests> RequestMap; + RequestMap requests_; + + // Used for progress updates on the UI thread, mapping download->id() to bytes + // received so far. Written to by the file thread and read by the UI thread. + typedef base::hash_map<int, int64> ProgressMap; + ProgressMap ui_progress_; + Lock progress_lock_; + + DISALLOW_COPY_AND_ASSIGN(DownloadFileManager); +}; + +#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_MANAGER_H_ diff --git a/chrome/browser/download/download_item.cc b/chrome/browser/download/download_item.cc new file mode 100644 index 0000000..d72b6d4 --- /dev/null +++ b/chrome/browser/download/download_item.cc @@ -0,0 +1,235 @@ +// Copyright (c) 2010 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_item.h" + +#include "base/logging.h" +#include "base/timer.h" +#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_util.h" +#include "chrome/browser/history/download_types.h" + +namespace { + +// Update frequency (milliseconds). +const int kUpdateTimeMs = 1000; + +} // namespace + +// Constructor for reading from the history service. +DownloadItem::DownloadItem(const DownloadCreateInfo& info) + : id_(-1), + full_path_(info.path), + url_(info.url), + referrer_url_(info.referrer_url), + mime_type_(info.mime_type), + original_mime_type_(info.original_mime_type), + total_bytes_(info.total_bytes), + received_bytes_(info.received_bytes), + start_tick_(base::TimeTicks()), + state_(static_cast<DownloadState>(info.state)), + start_time_(info.start_time), + db_handle_(info.db_handle), + manager_(NULL), + is_paused_(false), + open_when_complete_(false), + safety_state_(SAFE), + auto_opened_(false), + original_name_(info.original_name), + render_process_id_(-1), + request_id_(-1), + save_as_(false), + is_otr_(false), + is_extension_install_(info.is_extension_install), + name_finalized_(false), + is_temporary_(false) { + if (state_ == IN_PROGRESS) + state_ = CANCELLED; + Init(false /* don't start progress timer */); +} + +// Constructor for DownloadItem created via user action in the main thread. +DownloadItem::DownloadItem(int32 download_id, + const FilePath& path, + int path_uniquifier, + const GURL& url, + const GURL& referrer_url, + const std::string& mime_type, + const std::string& original_mime_type, + const FilePath& original_name, + const base::Time start_time, + int64 download_size, + int render_process_id, + int request_id, + bool is_dangerous, + bool save_as, + bool is_otr, + bool is_extension_install, + bool is_temporary) + : id_(download_id), + full_path_(path), + path_uniquifier_(path_uniquifier), + url_(url), + referrer_url_(referrer_url), + mime_type_(mime_type), + original_mime_type_(original_mime_type), + total_bytes_(download_size), + received_bytes_(0), + start_tick_(base::TimeTicks::Now()), + state_(IN_PROGRESS), + start_time_(start_time), + db_handle_(DownloadManager::kUninitializedHandle), + manager_(NULL), + is_paused_(false), + open_when_complete_(false), + safety_state_(is_dangerous ? DANGEROUS : SAFE), + auto_opened_(false), + original_name_(original_name), + render_process_id_(render_process_id), + request_id_(request_id), + save_as_(save_as), + is_otr_(is_otr), + is_extension_install_(is_extension_install), + name_finalized_(false), + is_temporary_(is_temporary) { + Init(true /* start progress timer */); +} + +void DownloadItem::Init(bool start_timer) { + file_name_ = full_path_.BaseName(); + if (start_timer) + StartProgressTimer(); +} + +DownloadItem::~DownloadItem() { + state_ = REMOVING; + UpdateObservers(); +} + +void DownloadItem::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void DownloadItem::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +void DownloadItem::UpdateObservers() { + FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this)); +} + +void DownloadItem::NotifyObserversDownloadFileCompleted() { + FOR_EACH_OBSERVER(Observer, observers_, OnDownloadFileCompleted(this)); +} + +void DownloadItem::NotifyObserversDownloadOpened() { + FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this)); +} + +// If we've received more data than we were expecting (bad server info?), revert +// to 'unknown size mode'. +void DownloadItem::UpdateSize(int64 bytes_so_far) { + received_bytes_ = bytes_so_far; + if (received_bytes_ > total_bytes_) + total_bytes_ = 0; +} + +// Updates from the download thread may have been posted while this download +// was being cancelled in the UI thread, so we'll accept them unless we're +// complete. +void DownloadItem::Update(int64 bytes_so_far) { + if (state_ == COMPLETE) { + NOTREACHED(); + return; + } + UpdateSize(bytes_so_far); + UpdateObservers(); +} + +// Triggered by a user action. +void DownloadItem::Cancel(bool update_history) { + if (state_ != IN_PROGRESS) { + // Small downloads might be complete before this method has a chance to run. + return; + } + state_ = CANCELLED; + UpdateObservers(); + StopProgressTimer(); + if (update_history) + manager_->DownloadCancelled(id_); +} + +void DownloadItem::Finished(int64 size) { + state_ = COMPLETE; + UpdateSize(size); + StopProgressTimer(); +} + +void DownloadItem::Remove(bool delete_on_disk) { + Cancel(true); + state_ = REMOVING; + if (delete_on_disk) + manager_->DeleteDownload(full_path_); + manager_->RemoveDownload(db_handle_); + // We have now been deleted. +} + +void DownloadItem::StartProgressTimer() { + update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdateTimeMs), this, + &DownloadItem::UpdateObservers); +} + +void DownloadItem::StopProgressTimer() { + update_timer_.Stop(); +} + +bool DownloadItem::TimeRemaining(base::TimeDelta* remaining) const { + if (total_bytes_ <= 0) + return false; // We never received the content_length for this download. + + int64 speed = CurrentSpeed(); + if (speed == 0) + return false; + + *remaining = + base::TimeDelta::FromSeconds((total_bytes_ - received_bytes_) / speed); + return true; +} + +int64 DownloadItem::CurrentSpeed() const { + base::TimeDelta diff = base::TimeTicks::Now() - start_tick_; + int64 diff_ms = diff.InMilliseconds(); + return diff_ms == 0 ? 0 : received_bytes_ * 1000 / diff_ms; +} + +int DownloadItem::PercentComplete() const { + int percent = -1; + if (total_bytes_ > 0) + percent = static_cast<int>(received_bytes_ * 100.0 / total_bytes_); + return percent; +} + +void DownloadItem::Rename(const FilePath& full_path) { + DCHECK(!full_path.empty()); + full_path_ = full_path; + file_name_ = full_path_.BaseName(); +} + +void DownloadItem::TogglePause() { + DCHECK(state_ == IN_PROGRESS); + manager_->PauseDownload(id_, !is_paused_); + is_paused_ = !is_paused_; + UpdateObservers(); +} + +FilePath DownloadItem::GetFileName() const { + if (safety_state_ == DownloadItem::SAFE) + return file_name_; + if (path_uniquifier_ > 0) { + FilePath name(original_name_); + download_util::AppendNumberToPath(&name, path_uniquifier_); + return name; + } + return original_name_; +} diff --git a/chrome/browser/download/download_item.h b/chrome/browser/download/download_item.h new file mode 100644 index 0000000..1a1b627 --- /dev/null +++ b/chrome/browser/download/download_item.h @@ -0,0 +1,299 @@ +// Copyright (c) 2010 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. +// +// Each download is represented by a DownloadItem, and all DownloadItems +// are owned by the DownloadManager which maintains a global list of all +// downloads. DownloadItems are created when a user initiates a download, +// and exist for the duration of the browser life time. +// +// Download observers: +// DownloadItem::Observer: +// - allows observers to receive notifications about one download from start +// to completion +// Use AddObserver() / RemoveObserver() on the appropriate download object to +// receive state updates. + +#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_H_ +#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/observer_list.h" +#include "base/time.h" +#include "base/timer.h" +#include "googleurl/src/gurl.h" + +class DownloadManager; +struct DownloadCreateInfo; + +// One DownloadItem per download. This is the model class that stores all the +// state for a download. Multiple views, such as a tab's download shelf and the +// Destination tab's download view, may refer to a given DownloadItem. +class DownloadItem { + public: + enum DownloadState { + IN_PROGRESS, + COMPLETE, + CANCELLED, + REMOVING + }; + + enum SafetyState { + SAFE = 0, + DANGEROUS, + DANGEROUS_BUT_VALIDATED // Dangerous but the user confirmed the download. + }; + + // Interface that observers of a particular download must implement in order + // to receive updates to the download's status. + class Observer { + public: + virtual void OnDownloadUpdated(DownloadItem* download) = 0; + + // Called when a downloaded file has been completed. + virtual void OnDownloadFileCompleted(DownloadItem* download) = 0; + + // Called when a downloaded file has been opened. + virtual void OnDownloadOpened(DownloadItem* download) = 0; + + protected: + virtual ~Observer() {} + }; + + // Constructing from persistent store: + explicit DownloadItem(const DownloadCreateInfo& info); + + // Constructing from user action: + DownloadItem(int32 download_id, + const FilePath& path, + int path_uniquifier, + const GURL& url, + const GURL& referrer_url, + const std::string& mime_type, + const std::string& original_mime_type, + const FilePath& original_name, + const base::Time start_time, + int64 download_size, + int render_process_id, + int request_id, + bool is_dangerous, + bool save_as, + bool is_otr, + bool is_extension_install, + bool is_temporary); + + ~DownloadItem(); + + void Init(bool start_timer); + + // Public API + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Notifies our observers periodically. + void UpdateObservers(); + + // Notifies our observers the downloaded file has been completed. + void NotifyObserversDownloadFileCompleted(); + + // Notifies our observers the downloaded file has been opened. + void NotifyObserversDownloadOpened(); + + // Received a new chunk of data + void Update(int64 bytes_so_far); + + // Cancel the download operation. We need to distinguish between cancels at + // exit (DownloadManager destructor) from user interface initiated cancels + // because at exit, the history system may not exist, and any updates to it + // require AddRef'ing the DownloadManager in the destructor which results in + // a DCHECK failure. Set 'update_history' to false when canceling from at + // exit to prevent this crash. This may result in a difference between the + // downloaded file's size on disk, and what the history system's last record + // of it is. At worst, we'll end up re-downloading a small portion of the file + // when resuming a download (assuming the server supports byte ranges). + void Cancel(bool update_history); + + // Download operation completed. + void Finished(int64 size); + + // The user wants to remove the download from the views and history. If + // |delete_file| is true, the file is deleted on the disk. + void Remove(bool delete_file); + + // Start/stop sending periodic updates to our observers + void StartProgressTimer(); + void StopProgressTimer(); + + // Simple calculation of the amount of time remaining to completion. Fills + // |*remaining| with the amount of time remaining if successful. Fails and + // returns false if we do not have the number of bytes or the speed so can + // not estimate. + bool TimeRemaining(base::TimeDelta* remaining) const; + + // Simple speed estimate in bytes/s + int64 CurrentSpeed() const; + + // Rough percent complete, -1 means we don't know (since we didn't receive a + // total size). + int PercentComplete() const; + + // Update the download's path, the actual file is renamed on the download + // thread. + void Rename(const FilePath& full_path); + + // Allow the user to temporarily pause a download or resume a paused download. + void TogglePause(); + + // Accessors + DownloadState state() const { return state_; } + FilePath file_name() const { return file_name_; } + void set_file_name(const FilePath& name) { file_name_ = name; } + FilePath full_path() const { return full_path_; } + void set_full_path(const FilePath& path) { full_path_ = path; } + int path_uniquifier() const { return path_uniquifier_; } + void set_path_uniquifier(int uniquifier) { path_uniquifier_ = uniquifier; } + GURL url() const { return url_; } + GURL referrer_url() const { return referrer_url_; } + std::string mime_type() const { return mime_type_; } + std::string original_mime_type() const { return original_mime_type_; } + int64 total_bytes() const { return total_bytes_; } + void set_total_bytes(int64 total_bytes) { total_bytes_ = total_bytes; } + int64 received_bytes() const { return received_bytes_; } + int32 id() const { return id_; } + base::Time start_time() const { return start_time_; } + void set_db_handle(int64 handle) { db_handle_ = handle; } + int64 db_handle() const { return db_handle_; } + DownloadManager* manager() const { return manager_; } + void set_manager(DownloadManager* manager) { manager_ = manager; } + bool is_paused() const { return is_paused_; } + void set_is_paused(bool pause) { is_paused_ = pause; } + bool open_when_complete() const { return open_when_complete_; } + void set_open_when_complete(bool open) { open_when_complete_ = open; } + int render_process_id() const { return render_process_id_; } + int request_id() const { return request_id_; } + SafetyState safety_state() const { return safety_state_; } + void set_safety_state(SafetyState safety_state) { + safety_state_ = safety_state; + } + bool auto_opened() { return auto_opened_; } + void set_auto_opened(bool auto_opened) { auto_opened_ = auto_opened; } + FilePath original_name() const { return original_name_; } + void set_original_name(const FilePath& name) { original_name_ = name; } + bool save_as() const { return save_as_; } + bool is_otr() const { return is_otr_; } + bool is_extension_install() const { return is_extension_install_; } + bool name_finalized() const { return name_finalized_; } + void set_name_finalized(bool name_finalized) { + name_finalized_ = name_finalized; + } + bool is_temporary() const { return is_temporary_; } + void set_is_temporary(bool is_temporary) { is_temporary_ = is_temporary; } + + // Returns the file-name that should be reported to the user, which is + // file_name_ for safe downloads and original_name_ for dangerous ones with + // the uniquifier number. + FilePath GetFileName() const; + + private: + // Internal helper for maintaining consistent received and total sizes. + void UpdateSize(int64 size); + + // Request ID assigned by the ResourceDispatcherHost. + int32 id_; + + // Full path to the downloaded file + FilePath full_path_; + + // A number that should be appended to the path to make it unique, or 0 if the + // path should be used as is. + int path_uniquifier_; + + // Short display version of the file + FilePath file_name_; + + // The URL from whence we came. + GURL url_; + + // The URL of the page that initiated the download. + GURL referrer_url_; + + // The mimetype of the download + std::string mime_type_; + + // The value of the content type header received when downloading + // this item. |mime_type_| may be different because of type sniffing. + std::string original_mime_type_; + + // Total bytes expected + int64 total_bytes_; + + // Current received bytes + int64 received_bytes_; + + // Start time for calculating remaining time + base::TimeTicks start_tick_; + + // The current state of this download + DownloadState state_; + + // The views of this item in the download shelf and download tab + ObserverList<Observer> observers_; + + // Time the download was started + base::Time start_time_; + + // Our persistent store handle + int64 db_handle_; + + // Timer for regularly updating our observers + base::RepeatingTimer<DownloadItem> update_timer_; + + // Our owning object + DownloadManager* manager_; + + // In progress downloads may be paused by the user, we note it here + bool is_paused_; + + // A flag for indicating if the download should be opened at completion. + bool open_when_complete_; + + // Whether the download is considered potentially safe or dangerous + // (executable files are typically considered dangerous). + SafetyState safety_state_; + + // Whether the download was auto-opened. We set this rather than using + // an observer as it's frequently possible for the download to be auto opened + // before the observer is added. + bool auto_opened_; + + // Dangerous download are given temporary names until the user approves them. + // This stores their original name. + FilePath original_name_; + + // For canceling or pausing requests. + int render_process_id_; + int request_id_; + + // True if the item was downloaded as a result of 'save as...' + bool save_as_; + + // True if the download was initiated in an incognito window. + bool is_otr_; + + // True if the item was downloaded for an extension installation. + bool is_extension_install_; + + // True if the filename is finalized. + bool name_finalized_; + + // True if the item was downloaded temporarily. + bool is_temporary_; + + DISALLOW_COPY_AND_ASSIGN(DownloadItem); +}; + +#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_H_ diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc index 2dc4c1e..457a34a 100644 --- a/chrome/browser/download/download_item_model.cc +++ b/chrome/browser/download/download_item_model.cc @@ -8,7 +8,7 @@ #include "base/i18n/number_formatting.h" #include "base/i18n/rtl.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/save_package.h" #include "chrome/common/time_format.h" #include "grit/generated_resources.h" diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc index c43f18e..26d1d54 100644 --- a/chrome/browser/download/download_manager.cc +++ b/chrome/browser/download/download_manager.cc @@ -9,48 +9,39 @@ #include "base/callback.h" #include "base/file_util.h" #include "base/logging.h" -#include "base/message_loop.h" #include "base/path_service.h" #include "base/rand_util.h" -#include "base/stl_util-inl.h" -#include "base/string_util.h" #include "base/sys_string_conversions.h" #include "base/task.h" -#include "base/thread.h" -#include "base/timer.h" #include "build/build_config.h" +#include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_thread.h" -#include "chrome/browser/download/download_file.h" +#include "chrome/browser/download/download_file_manager.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_util.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_install_ui.h" #include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/history/download_types.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/platform_util.h" -#include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" -#include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/browser/tab_contents/infobar_delegate.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_util.h" -#include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" -#include "chrome/common/extensions/extension.h" -#include "chrome/common/extensions/user_script.h" #include "chrome/common/notification_service.h" #include "chrome/common/notification_type.h" #include "chrome/common/pref_names.h" #include "googleurl/src/gurl.h" -#include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "net/base/mime_util.h" #include "net/base/net_util.h" -#include "net/url_request/url_request_context.h" #if defined(OS_WIN) #include "app/win_util.h" @@ -60,25 +51,6 @@ namespace { -// Periodically update our observers. -class DownloadItemUpdateTask : public Task { - public: - explicit DownloadItemUpdateTask(DownloadItem* item) : item_(item) {} - void Run() { if (item_) item_->UpdateObservers(); } - - private: - DownloadItem* item_; -}; - -// Update frequency (milliseconds). -const int kUpdateTimeMs = 1000; - -// Our download table ID starts at 1, so we use 0 to represent a download that -// has started, but has not yet had its data persisted in the table. We use fake -// database handles in incognito mode starting at -1 and progressively getting -// more negative. -const int kUninitializedHandle = 0; - // Used to sort download items based on descending start time. bool CompareStartTime(DownloadItem* first, DownloadItem* second) { return first->start_time() > second->start_time(); @@ -94,226 +66,12 @@ void DeleteDownloadedFile(const FilePath& path) { } // namespace -// DownloadItem implementation ------------------------------------------------- - -// Constructor for reading from the history service. -DownloadItem::DownloadItem(const DownloadCreateInfo& info) - : id_(-1), - full_path_(info.path), - url_(info.url), - referrer_url_(info.referrer_url), - mime_type_(info.mime_type), - original_mime_type_(info.original_mime_type), - total_bytes_(info.total_bytes), - received_bytes_(info.received_bytes), - start_tick_(base::TimeTicks()), - state_(static_cast<DownloadState>(info.state)), - start_time_(info.start_time), - db_handle_(info.db_handle), - manager_(NULL), - is_paused_(false), - open_when_complete_(false), - safety_state_(SAFE), - auto_opened_(false), - original_name_(info.original_name), - render_process_id_(-1), - request_id_(-1), - save_as_(false), - is_otr_(false), - is_extension_install_(info.is_extension_install), - name_finalized_(false), - is_temporary_(false) { - if (state_ == IN_PROGRESS) - state_ = CANCELLED; - Init(false /* don't start progress timer */); -} - -// Constructor for DownloadItem created via user action in the main thread. -DownloadItem::DownloadItem(int32 download_id, - const FilePath& path, - int path_uniquifier, - const GURL& url, - const GURL& referrer_url, - const std::string& mime_type, - const std::string& original_mime_type, - const FilePath& original_name, - const base::Time start_time, - int64 download_size, - int render_process_id, - int request_id, - bool is_dangerous, - bool save_as, - bool is_otr, - bool is_extension_install, - bool is_temporary) - : id_(download_id), - full_path_(path), - path_uniquifier_(path_uniquifier), - url_(url), - referrer_url_(referrer_url), - mime_type_(mime_type), - original_mime_type_(original_mime_type), - total_bytes_(download_size), - received_bytes_(0), - start_tick_(base::TimeTicks::Now()), - state_(IN_PROGRESS), - start_time_(start_time), - db_handle_(kUninitializedHandle), - manager_(NULL), - is_paused_(false), - open_when_complete_(false), - safety_state_(is_dangerous ? DANGEROUS : SAFE), - auto_opened_(false), - original_name_(original_name), - render_process_id_(render_process_id), - request_id_(request_id), - save_as_(save_as), - is_otr_(is_otr), - is_extension_install_(is_extension_install), - name_finalized_(false), - is_temporary_(is_temporary) { - Init(true /* start progress timer */); -} - -void DownloadItem::Init(bool start_timer) { - file_name_ = full_path_.BaseName(); - if (start_timer) - StartProgressTimer(); -} - -DownloadItem::~DownloadItem() { - state_ = REMOVING; - UpdateObservers(); -} - -void DownloadItem::AddObserver(Observer* observer) { - observers_.AddObserver(observer); -} - -void DownloadItem::RemoveObserver(Observer* observer) { - observers_.RemoveObserver(observer); -} - -void DownloadItem::UpdateObservers() { - FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this)); -} - -void DownloadItem::NotifyObserversDownloadFileCompleted() { - FOR_EACH_OBSERVER(Observer, observers_, OnDownloadFileCompleted(this)); -} - -void DownloadItem::NotifyObserversDownloadOpened() { - FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this)); -} - -// If we've received more data than we were expecting (bad server info?), revert -// to 'unknown size mode'. -void DownloadItem::UpdateSize(int64 bytes_so_far) { - received_bytes_ = bytes_so_far; - if (received_bytes_ > total_bytes_) - total_bytes_ = 0; -} - -// Updates from the download thread may have been posted while this download -// was being cancelled in the UI thread, so we'll accept them unless we're -// complete. -void DownloadItem::Update(int64 bytes_so_far) { - if (state_ == COMPLETE) { - NOTREACHED(); - return; - } - UpdateSize(bytes_so_far); - UpdateObservers(); -} - -// Triggered by a user action. -void DownloadItem::Cancel(bool update_history) { - if (state_ != IN_PROGRESS) { - // Small downloads might be complete before this method has a chance to run. - return; - } - state_ = CANCELLED; - UpdateObservers(); - StopProgressTimer(); - if (update_history) - manager_->DownloadCancelled(id_); -} - -void DownloadItem::Finished(int64 size) { - state_ = COMPLETE; - UpdateSize(size); - StopProgressTimer(); -} - -void DownloadItem::Remove(bool delete_on_disk) { - Cancel(true); - state_ = REMOVING; - if (delete_on_disk) - manager_->DeleteDownload(full_path_); - manager_->RemoveDownload(db_handle_); - // We have now been deleted. -} - -void DownloadItem::StartProgressTimer() { - update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdateTimeMs), this, - &DownloadItem::UpdateObservers); -} - -void DownloadItem::StopProgressTimer() { - update_timer_.Stop(); -} - -bool DownloadItem::TimeRemaining(base::TimeDelta* remaining) const { - if (total_bytes_ <= 0) - return false; // We never received the content_length for this download. - - int64 speed = CurrentSpeed(); - if (speed == 0) - return false; - - *remaining = - base::TimeDelta::FromSeconds((total_bytes_ - received_bytes_) / speed); - return true; -} - -int64 DownloadItem::CurrentSpeed() const { - base::TimeDelta diff = base::TimeTicks::Now() - start_tick_; - int64 diff_ms = diff.InMilliseconds(); - return diff_ms == 0 ? 0 : received_bytes_ * 1000 / diff_ms; -} - -int DownloadItem::PercentComplete() const { - int percent = -1; - if (total_bytes_ > 0) - percent = static_cast<int>(received_bytes_ * 100.0 / total_bytes_); - return percent; -} - -void DownloadItem::Rename(const FilePath& full_path) { - DCHECK(!full_path.empty()); - full_path_ = full_path; - file_name_ = full_path_.BaseName(); -} - -void DownloadItem::TogglePause() { - DCHECK(state_ == IN_PROGRESS); - manager_->PauseDownload(id_, !is_paused_); - is_paused_ = !is_paused_; - UpdateObservers(); -} - -FilePath DownloadItem::GetFileName() const { - if (safety_state_ == DownloadItem::SAFE) - return file_name_; - if (path_uniquifier_ > 0) { - FilePath name(original_name_); - download_util::AppendNumberToPath(&name, path_uniquifier_); - return name; - } - return original_name_; -} - -// DownloadManager implementation ---------------------------------------------- +// Our download table ID starts at 1, so we use 0 to represent a download that +// has started, but has not yet had its data persisted in the table. We use fake +// database handles in incognito mode starting at -1 and progressively getting +// more negative. +// static +const int DownloadManager::kUninitializedHandle = 0; // static void DownloadManager::RegisterUserPrefs(PrefService* prefs) { diff --git a/chrome/browser/download/download_manager.h b/chrome/browser/download/download_manager.h index ee9dff8..704012d 100644 --- a/chrome/browser/download/download_manager.h +++ b/chrome/browser/download/download_manager.h @@ -7,18 +7,10 @@ // the downloads view in the Destinations tab. There is one DownloadManager per // active profile in Chrome. // -// Each download is represented by a DownloadItem, and all DownloadItems -// are owned by the DownloadManager which maintains a global list of all -// downloads. DownloadItems are created when a user initiates a download, -// and exist for the duration of the browser life time. -// // Download observers: // Objects that are interested in notifications about new downloads, or progress // updates for a given download must implement one of the download observer // interfaces: -// DownloadItem::Observer: -// - allows observers to receive notifications about one download from start -// to completion // DownloadManager::Observer: // - allows observers, primarily views, to be notified when changes to the // set of all downloads (such as new downloads, or deletes) occur @@ -42,20 +34,16 @@ #include "base/basictypes.h" #include "base/file_path.h" -#include "base/hash_tables.h" #include "base/observer_list.h" #include "base/ref_counted.h" #include "base/time.h" -#include "base/timer.h" #include "chrome/browser/cancelable_request.h" -#include "chrome/browser/history/download_types.h" #include "chrome/browser/history/history.h" #include "chrome/browser/pref_member.h" #include "chrome/browser/shell_dialogs.h" class DownloadFileManager; -class DownloadItemView; -class DownloadManager; +class DownloadItem; class GURL; class PrefService; class Profile; @@ -64,282 +52,6 @@ class URLRequestContextGetter; class TabContents; struct DownloadSaveInfo; -namespace base { -class Thread; -} - -// DownloadItem ---------------------------------------------------------------- - -// One DownloadItem per download. This is the model class that stores all the -// state for a download. Multiple views, such as a tab's download shelf and the -// Destination tab's download view, may refer to a given DownloadItem. -class DownloadItem { - public: - enum DownloadState { - IN_PROGRESS, - COMPLETE, - CANCELLED, - REMOVING - }; - - enum SafetyState { - SAFE = 0, - DANGEROUS, - DANGEROUS_BUT_VALIDATED // Dangerous but the user confirmed the download. - }; - - // Interface that observers of a particular download must implement in order - // to receive updates to the download's status. - class Observer { - public: - virtual void OnDownloadUpdated(DownloadItem* download) = 0; - - // Called when a downloaded file has been completed. - virtual void OnDownloadFileCompleted(DownloadItem* download) = 0; - - // Called when a downloaded file has been opened. - virtual void OnDownloadOpened(DownloadItem* download) = 0; - - protected: - virtual ~Observer() {} - }; - - // Constructing from persistent store: - explicit DownloadItem(const DownloadCreateInfo& info); - - // Constructing from user action: - DownloadItem(int32 download_id, - const FilePath& path, - int path_uniquifier, - const GURL& url, - const GURL& referrer_url, - const std::string& mime_type, - const std::string& original_mime_type, - const FilePath& original_name, - const base::Time start_time, - int64 download_size, - int render_process_id, - int request_id, - bool is_dangerous, - bool save_as, - bool is_otr, - bool is_extension_install, - bool is_temporary); - - ~DownloadItem(); - - void Init(bool start_timer); - - // Public API - - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); - - // Notifies our observers periodically. - void UpdateObservers(); - - // Notifies our observers the downloaded file has been completed. - void NotifyObserversDownloadFileCompleted(); - - // Notifies our observers the downloaded file has been opened. - void NotifyObserversDownloadOpened(); - - // Received a new chunk of data - void Update(int64 bytes_so_far); - - // Cancel the download operation. We need to distinguish between cancels at - // exit (DownloadManager destructor) from user interface initiated cancels - // because at exit, the history system may not exist, and any updates to it - // require AddRef'ing the DownloadManager in the destructor which results in - // a DCHECK failure. Set 'update_history' to false when canceling from at - // exit to prevent this crash. This may result in a difference between the - // downloaded file's size on disk, and what the history system's last record - // of it is. At worst, we'll end up re-downloading a small portion of the file - // when resuming a download (assuming the server supports byte ranges). - void Cancel(bool update_history); - - // Download operation completed. - void Finished(int64 size); - - // The user wants to remove the download from the views and history. If - // |delete_file| is true, the file is deleted on the disk. - void Remove(bool delete_file); - - // Start/stop sending periodic updates to our observers - void StartProgressTimer(); - void StopProgressTimer(); - - // Simple calculation of the amount of time remaining to completion. Fills - // |*remaining| with the amount of time remaining if successful. Fails and - // returns false if we do not have the number of bytes or the speed so can - // not estimate. - bool TimeRemaining(base::TimeDelta* remaining) const; - - // Simple speed estimate in bytes/s - int64 CurrentSpeed() const; - - // Rough percent complete, -1 means we don't know (since we didn't receive a - // total size). - int PercentComplete() const; - - // Update the download's path, the actual file is renamed on the download - // thread. - void Rename(const FilePath& full_path); - - // Allow the user to temporarily pause a download or resume a paused download. - void TogglePause(); - - // Accessors - DownloadState state() const { return state_; } - FilePath file_name() const { return file_name_; } - void set_file_name(const FilePath& name) { file_name_ = name; } - FilePath full_path() const { return full_path_; } - void set_full_path(const FilePath& path) { full_path_ = path; } - int path_uniquifier() const { return path_uniquifier_; } - void set_path_uniquifier(int uniquifier) { path_uniquifier_ = uniquifier; } - GURL url() const { return url_; } - GURL referrer_url() const { return referrer_url_; } - std::string mime_type() const { return mime_type_; } - std::string original_mime_type() const { return original_mime_type_; } - int64 total_bytes() const { return total_bytes_; } - void set_total_bytes(int64 total_bytes) { total_bytes_ = total_bytes; } - int64 received_bytes() const { return received_bytes_; } - int32 id() const { return id_; } - base::Time start_time() const { return start_time_; } - void set_db_handle(int64 handle) { db_handle_ = handle; } - int64 db_handle() const { return db_handle_; } - DownloadManager* manager() const { return manager_; } - void set_manager(DownloadManager* manager) { manager_ = manager; } - bool is_paused() const { return is_paused_; } - void set_is_paused(bool pause) { is_paused_ = pause; } - bool open_when_complete() const { return open_when_complete_; } - void set_open_when_complete(bool open) { open_when_complete_ = open; } - int render_process_id() const { return render_process_id_; } - int request_id() const { return request_id_; } - SafetyState safety_state() const { return safety_state_; } - void set_safety_state(SafetyState safety_state) { - safety_state_ = safety_state; - } - bool auto_opened() { return auto_opened_; } - void set_auto_opened(bool auto_opened) { auto_opened_ = auto_opened; } - FilePath original_name() const { return original_name_; } - void set_original_name(const FilePath& name) { original_name_ = name; } - bool save_as() const { return save_as_; } - bool is_otr() const { return is_otr_; } - bool is_extension_install() const { return is_extension_install_; } - bool name_finalized() const { return name_finalized_; } - void set_name_finalized(bool name_finalized) { - name_finalized_ = name_finalized; - } - bool is_temporary() const { return is_temporary_; } - void set_is_temporary(bool is_temporary) { is_temporary_ = is_temporary; } - - // Returns the file-name that should be reported to the user, which is - // file_name_ for safe downloads and original_name_ for dangerous ones with - // the uniquifier number. - FilePath GetFileName() const; - - private: - // Internal helper for maintaining consistent received and total sizes. - void UpdateSize(int64 size); - - // Request ID assigned by the ResourceDispatcherHost. - int32 id_; - - // Full path to the downloaded file - FilePath full_path_; - - // A number that should be appended to the path to make it unique, or 0 if the - // path should be used as is. - int path_uniquifier_; - - // Short display version of the file - FilePath file_name_; - - // The URL from whence we came. - GURL url_; - - // The URL of the page that initiated the download. - GURL referrer_url_; - - // The mimetype of the download - std::string mime_type_; - - // The value of the content type header received when downloading - // this item. |mime_type_| may be different because of type sniffing. - std::string original_mime_type_; - - // Total bytes expected - int64 total_bytes_; - - // Current received bytes - int64 received_bytes_; - - // Start time for calculating remaining time - base::TimeTicks start_tick_; - - // The current state of this download - DownloadState state_; - - // The views of this item in the download shelf and download tab - ObserverList<Observer> observers_; - - // Time the download was started - base::Time start_time_; - - // Our persistent store handle - int64 db_handle_; - - // Timer for regularly updating our observers - base::RepeatingTimer<DownloadItem> update_timer_; - - // Our owning object - DownloadManager* manager_; - - // In progress downloads may be paused by the user, we note it here - bool is_paused_; - - // A flag for indicating if the download should be opened at completion. - bool open_when_complete_; - - // Whether the download is considered potentially safe or dangerous - // (executable files are typically considered dangerous). - SafetyState safety_state_; - - // Whether the download was auto-opened. We set this rather than using - // an observer as it's frequently possible for the download to be auto opened - // before the observer is added. - bool auto_opened_; - - // Dangerous download are given temporary names until the user approves them. - // This stores their original name. - FilePath original_name_; - - // For canceling or pausing requests. - int render_process_id_; - int request_id_; - - // True if the item was downloaded as a result of 'save as...' - bool save_as_; - - // True if the download was initiated in an incognito window. - bool is_otr_; - - // True if the item was downloaded for an extension installation. - bool is_extension_install_; - - // True if the filename is finalized. - bool name_finalized_; - - // True if the item was downloaded temporarily. - bool is_temporary_; - - DISALLOW_COPY_AND_ASSIGN(DownloadItem); -}; - - -// DownloadManager ------------------------------------------------------------- - // Browser's download manager: manages all downloads and destination view. class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>, public SelectFileDialog::Listener { @@ -347,6 +59,10 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>, friend class DownloadManagerTest; public: + // A fake download table ID which representas a download that has started, + // but is not yet in the table. + static const int kUninitializedHandle; + DownloadManager(); static void RegisterUserPrefs(PrefService* prefs); diff --git a/chrome/browser/download/download_manager_unittest.cc b/chrome/browser/download/download_manager_unittest.cc index 5ff1786..c971115 100644 --- a/chrome/browser/download/download_manager_unittest.cc +++ b/chrome/browser/download/download_manager_unittest.cc @@ -8,6 +8,7 @@ #include "build/build_config.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/download/download_manager.h" +#include "chrome/browser/history/download_types.h" #include "chrome/common/pref_names.h" #include "chrome/test/testing_profile.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/download/download_shelf.cc b/chrome/browser/download/download_shelf.cc index ec67f0e..fa6ab09 100644 --- a/chrome/browser/download/download_shelf.cc +++ b/chrome/browser/download/download_shelf.cc @@ -8,6 +8,7 @@ #include "base/file_util.h" #include "chrome/browser/browser.h" #include "chrome/browser/dom_ui/downloads_ui.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/download_util.h" diff --git a/chrome/browser/download/download_types.h b/chrome/browser/download/download_types.h new file mode 100644 index 0000000..de8bfc8 --- /dev/null +++ b/chrome/browser/download/download_types.h @@ -0,0 +1,37 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_TYPES_H_ +#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_TYPES_H_ + +#include <vector> + +#include "base/file_path.h" +#include "base/linked_ptr.h" +#include "base/lock.h" +#include "net/base/file_stream.h" + +namespace net { +class IOBuffer; +} + +// DownloadBuffer is created and populated on the IO thread, and passed to the +// file thread for writing. In order to avoid flooding the file thread with too +// many small write messages, each write is appended to the DownloadBuffer while +// waiting for the task to run on the file thread. Access to the write buffers +// is synchronized via the lock. Each entry in 'contents' represents one data +// buffer and its size in bytes. +struct DownloadBuffer { + Lock lock; + typedef std::pair<net::IOBuffer*, int> Contents; + std::vector<Contents> contents; +}; + +// Holds the information about how to save a download file. +struct DownloadSaveInfo { + FilePath file_path; + linked_ptr<net::FileStream> file_stream; +}; + +#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_TYPES_H_ diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc index 591eb83..a3e064f 100644 --- a/chrome/browser/download/download_util.cc +++ b/chrome/browser/download/download_util.cc @@ -22,6 +22,7 @@ #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_manager.h" #include "chrome/common/chrome_paths.h" diff --git a/chrome/browser/download/drag_download_file.cc b/chrome/browser/download/drag_download_file.cc index 8267621..4b2b370 100644 --- a/chrome/browser/download/drag_download_file.cc +++ b/chrome/browser/download/drag_download_file.cc @@ -8,7 +8,7 @@ #include "base/message_loop.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/download/download_file.h" -#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "net/base/file_stream.h" diff --git a/chrome/browser/download/drag_download_file.h b/chrome/browser/download/drag_download_file.h index 31064ec..4ea3cdf 100644 --- a/chrome/browser/download/drag_download_file.h +++ b/chrome/browser/download/drag_download_file.h @@ -9,13 +9,14 @@ #include "base/file_path.h" #include "base/linked_ptr.h" #include "chrome/browser/download/download_file.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_manager.h" #include "googleurl/src/gurl.h" class TabContents; namespace net { -class FileSteram; +class FileStream; } class DragDownloadFile : public DownloadFileProvider, diff --git a/chrome/browser/download/save_package.cc b/chrome/browser/download/save_package.cc index a9a8a6f..7be57c2 100644 --- a/chrome/browser/download/save_package.cc +++ b/chrome/browser/download/save_package.cc @@ -17,6 +17,7 @@ #include "base/thread.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_thread.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/download_shelf.h" diff --git a/chrome/browser/gtk/custom_drag.cc b/chrome/browser/gtk/custom_drag.cc index 282e316..9eb3b85 100644 --- a/chrome/browser/gtk/custom_drag.cc +++ b/chrome/browser/gtk/custom_drag.cc @@ -6,7 +6,7 @@ #include "app/gtk_dnd_util.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/gtk/bookmark_utils_gtk.h" #include "gfx/gtk_util.h" #include "googleurl/src/gurl.h" diff --git a/chrome/browser/gtk/download_item_gtk.cc b/chrome/browser/gtk/download_item_gtk.cc index e7a8ddc..6744af0 100644 --- a/chrome/browser/gtk/download_item_gtk.cc +++ b/chrome/browser/gtk/download_item_gtk.cc @@ -17,6 +17,7 @@ #include "base/time.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/download_shelf.h" diff --git a/chrome/browser/gtk/download_item_gtk.h b/chrome/browser/gtk/download_item_gtk.h index a701d99..1b793dc 100644 --- a/chrome/browser/gtk/download_item_gtk.h +++ b/chrome/browser/gtk/download_item_gtk.h @@ -13,7 +13,7 @@ #include "app/gtk_signal.h" #include "base/scoped_ptr.h" #include "base/time.h" -#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/icon_manager.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" diff --git a/chrome/browser/gtk/download_shelf_gtk.cc b/chrome/browser/gtk/download_shelf_gtk.cc index f7ef409..a6c2a69 100644 --- a/chrome/browser/gtk/download_shelf_gtk.cc +++ b/chrome/browser/gtk/download_shelf_gtk.cc @@ -7,6 +7,7 @@ #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "chrome/browser/browser.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_util.h" #include "chrome/browser/gtk/browser_window_gtk.h" diff --git a/chrome/browser/history/download_database.cc b/chrome/browser/history/download_database.cc index 26780ad..aa3dbde 100644 --- a/chrome/browser/history/download_database.cc +++ b/chrome/browser/history/download_database.cc @@ -12,7 +12,7 @@ #include "base/file_path.h" #include "base/utf_string_conversions.h" #include "build/build_config.h" -#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/history/download_types.h" // Download schema: diff --git a/chrome/browser/history/history_unittest.cc b/chrome/browser/history/history_unittest.cc index 24b4119..c8db05a 100644 --- a/chrome/browser/history/history_unittest.cc +++ b/chrome/browser/history/history_unittest.cc @@ -32,7 +32,7 @@ #include "base/string_util.h" #include "base/task.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/history/history.h" #include "chrome/browser/history/history_backend.h" #include "chrome/browser/history/history_database.h" diff --git a/chrome/browser/renderer_host/download_resource_handler.cc b/chrome/browser/renderer_host/download_resource_handler.cc index 73d9cec..0b45695 100644 --- a/chrome/browser/renderer_host/download_resource_handler.cc +++ b/chrome/browser/renderer_host/download_resource_handler.cc @@ -6,8 +6,9 @@ #include "base/logging.h" #include "chrome/browser/chrome_thread.h" -#include "chrome/browser/download/download_file.h" -#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_item.h" +#include "chrome/browser/download/download_file_manager.h" +#include "chrome/browser/history/download_types.h" #include "chrome/browser/renderer_host/global_request_id.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/common/resource_response.h" diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc index eab9da82..cca59a1 100644 --- a/chrome/browser/renderer_host/resource_dispatcher_host.cc +++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc @@ -17,7 +17,7 @@ #include "chrome/browser/cert_store.h" #include "chrome/browser/child_process_security_policy.h" #include "chrome/browser/cross_site_request_manager.h" -#include "chrome/browser/download/download_file.h" +#include "chrome/browser/download/download_file_manager.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/download_request_limiter.h" #include "chrome/browser/download/save_file_manager.h" diff --git a/chrome/browser/views/download_item_view.h b/chrome/browser/views/download_item_view.h index 366dc1c..ffede2c 100644 --- a/chrome/browser/views/download_item_view.h +++ b/chrome/browser/views/download_item_view.h @@ -24,6 +24,7 @@ #include "base/time.h" #include "base/timer.h" #include "chrome/browser/cancelable_request.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/icon_manager.h" #include "gfx/font.h" diff --git a/chrome/browser/views/download_shelf_view.cc b/chrome/browser/views/download_shelf_view.cc index d727d43..f0c37f1 100644 --- a/chrome/browser/views/download_shelf_view.cc +++ b/chrome/browser/views/download_shelf_view.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_theme_provider.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/tab_contents/navigation_entry.h" diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 7da139b..dde71ad 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1136,6 +1136,10 @@ 'browser/download/download_exe.cc', 'browser/download/download_file.cc', 'browser/download/download_file.h', + 'browser/download/download_file_manager.cc', + 'browser/download/download_file_manager.h', + 'browser/download/download_item.cc', + 'browser/download/download_item.h', 'browser/download/download_item_model.cc', 'browser/download/download_item_model.h', 'browser/download/download_manager.cc', @@ -1147,6 +1151,7 @@ 'browser/download/download_shelf.cc', 'browser/download/download_shelf.h', 'browser/download/download_started_animation.h', + 'browser/download/download_types.h', 'browser/download/download_util.cc', 'browser/download/download_util.h', 'browser/download/drag_download_file.cc', diff --git a/chrome/test/ui_test_utils.cc b/chrome/test/ui_test_utils.cc index f9f2d04..c464229 100644 --- a/chrome/test/ui_test_utils.cc +++ b/chrome/test/ui_test_utils.cc @@ -16,6 +16,7 @@ #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/dom_operation_notification_details.h" +#include "chrome/browser/download/download_item.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" |