// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // The DownloadManager object manages the process of downloading, including // updates to the history system and providing the information for displaying // the downloads view in the Destinations tab. There is one DownloadManager per // active profile in Chrome. // // 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: // DownloadManager::Observer: // - allows observers, primarily views, to be notified when changes to the // set of all downloads (such as new downloads, or deletes) occur // Use AddObserver() / RemoveObserver() on the appropriate download object to // receive state updates. // // Download state persistence: // The DownloadManager uses the history service for storing persistent // information about the state of all downloads. The history system maintains a // separate table for this called 'downloads'. At the point that the // DownloadManager is constructed, we query the history service for the state of // all persisted downloads. #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_H_ #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_H_ #pragma once #include <map> #include <set> #include <string> #include <vector> #include "base/basictypes.h" #include "base/file_path.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/scoped_ptr.h" #include "base/time.h" #include "chrome/browser/download/download_status_updater_delegate.h" #include "chrome/browser/ui/shell_dialogs.h" #include "content/browser/browser_thread.h" class DownloadFileManager; class DownloadHistory; class DownloadItem; class DownloadPrefs; class DownloadStatusUpdater; class GURL; class Profile; class ResourceDispatcherHost; class TabContents; struct DownloadCreateInfo; struct DownloadSaveInfo; namespace net { class URLRequestContextGetter; } // Browser's download manager: manages all downloads and destination view. class DownloadManager : public base::RefCountedThreadSafe<DownloadManager, BrowserThread::DeleteOnUIThread>, public DownloadStatusUpdaterDelegate, public SelectFileDialog::Listener { public: explicit DownloadManager(DownloadStatusUpdater* status_updater); // Shutdown the download manager. Must be called before destruction. void Shutdown(); // Interface to implement for observers that wish to be informed of changes // to the DownloadManager's collection of downloads. class Observer { public: // New or deleted download, observers should query us for the current set // of downloads. virtual void ModelChanged() = 0; // Called when the DownloadManager is being destroyed to prevent Observers // from calling back to a stale pointer. virtual void ManagerGoingDown() {} // Called immediately after the DownloadManager puts up a select file // dialog. // |id| indicates which download opened the dialog. virtual void SelectFileDialogDisplayed(int32 id) {} protected: virtual ~Observer() {} }; // Return all temporary downloads that reside in the specified directory. void GetTemporaryDownloads(const FilePath& dir_path, std::vector<DownloadItem*>* result); // Return all non-temporary downloads in the specified directory that are // are in progress or have completed. void GetAllDownloads(const FilePath& dir_path, std::vector<DownloadItem*>* result); // Return all non-temporary downloads in the specified directory that are // in-progress (including dangerous downloads waiting for user confirmation). void GetCurrentDownloads(const FilePath& dir_path, std::vector<DownloadItem*>* result); // Returns all non-temporary downloads matching |query|. Empty query matches // everything. void SearchDownloads(const string16& query, std::vector<DownloadItem*>* result); // Returns true if initialized properly. bool Init(Profile* profile); // Notifications sent from the download thread to the UI thread void StartDownload(DownloadCreateInfo* info); void UpdateDownload(int32 download_id, int64 size); // |hash| is sha256 hash for the downloaded file. It is empty when the hash // is not available. void OnResponseCompleted(int32 download_id, int64 size, int os_error, const std::string& hash); // Called from a view when a user clicks a UI button or link. void DownloadCancelled(int32 download_id); void PauseDownload(int32 download_id, bool pause); void RemoveDownload(int64 download_handle); // Determine if the download is ready for completion, i.e. has had // all data saved, and completed the filename determination and // history insertion. bool IsDownloadReadyForCompletion(DownloadItem* download); // If all pre-requisites have been met, complete download processing, i.e. // do internal cleanup, file rename, and potentially auto-open. // (Dangerous downloads still may block on user acceptance after this // point.) void MaybeCompleteDownload(DownloadItem* download); // Called when the download is renamed to its final name. // |uniquifier| is a number used to make unique names for the file. It is // only valid for the DANGEROUS_BUT_VALIDATED state of the download item. void OnDownloadRenamedToFinalName(int download_id, const FilePath& full_path, int uniquifier); // Remove downloads after remove_begin (inclusive) and before remove_end // (exclusive). You may pass in null Time values to do an unbounded delete // in either direction. int RemoveDownloadsBetween(const base::Time remove_begin, const base::Time remove_end); // Remove downloads will delete all downloads that have a timestamp that is // the same or more recent than |remove_begin|. The number of downloads // deleted is returned back to the caller. int RemoveDownloads(const base::Time remove_begin); // Remove all downloads will delete all downloads. The number of downloads // deleted is returned back to the caller. int RemoveAllDownloads(); // Final download manager transition for download: Update the download // history and remove the download from |active_downloads_|. void DownloadCompleted(int32 download_id); // Called when a Save Page As download is started. Transfers ownership // of |download_item| to the DownloadManager. void SavePageAsDownloadStarted(DownloadItem* download_item); // Download the object at the URL. Used in cases such as "Save Link As..." void DownloadUrl(const GURL& url, const GURL& referrer, const std::string& referrer_encoding, TabContents* tab_contents); // Download the object at the URL and save it to the specified path. The // download is treated as the temporary download and thus will not appear // in the download history. Used in cases such as drag and drop. void DownloadUrlToFile(const GURL& url, const GURL& referrer, const std::string& referrer_encoding, const DownloadSaveInfo& save_info, TabContents* tab_contents); // Allow objects to observe the download creation process. void AddObserver(Observer* observer); // Remove a download observer from ourself. void RemoveObserver(Observer* observer); // Methods called on completion of a query sent to the history system. void OnQueryDownloadEntriesComplete( std::vector<DownloadCreateInfo>* entries); void OnCreateDownloadEntryComplete( DownloadCreateInfo info, int64 db_handle); // Display a new download in the appropriate browser UI. void ShowDownloadInBrowser(const DownloadCreateInfo& info, DownloadItem* download); // The number of in progress (including paused) downloads. int in_progress_count() const { return static_cast<int>(in_progress_.size()); } Profile* profile() { return profile_; } DownloadHistory* download_history() { return download_history_.get(); } DownloadPrefs* download_prefs() { return download_prefs_.get(); } // Creates the download item. Must be called on the UI thread. void CreateDownloadItem(DownloadCreateInfo* info); // Clears the last download path, used to initialize "save as" dialogs. void ClearLastDownloadPath(); // Tests if a file type should be opened automatically. bool ShouldOpenFileBasedOnExtension(const FilePath& path) const; // Overridden from DownloadStatusUpdaterDelegate: virtual bool IsDownloadProgressKnown(); virtual int64 GetInProgressDownloadCount(); virtual int64 GetReceivedDownloadBytes(); virtual int64 GetTotalDownloadBytes(); // Overridden from SelectFileDialog::Listener: virtual void FileSelected(const FilePath& path, int index, void* params); virtual void FileSelectionCanceled(void* params); // Called when the user has validated the download of a dangerous file. void DangerousDownloadValidated(DownloadItem* download); // Callback function after url is checked with safebrowsing service. void CheckDownloadUrlDone(DownloadCreateInfo* info, bool is_dangerous_url); // Callback function after download file hash is checked with safebrowsing // service. void CheckDownloadHashDone(int32 download_id, bool is_dangerous_hash); private: // For testing. friend class DownloadManagerTest; friend class MockDownloadManager; // This class is used to let an incognito DownloadManager observe changes to // a normal DownloadManager, to propagate ModelChanged() calls from the parent // DownloadManager to the observers of the incognito DownloadManager. class OtherDownloadManagerObserver : public Observer { public: explicit OtherDownloadManagerObserver( DownloadManager* observing_download_manager); virtual ~OtherDownloadManagerObserver(); // Observer interface. virtual void ModelChanged(); virtual void ManagerGoingDown(); private: // The incognito download manager. DownloadManager* observing_download_manager_; // The original profile's download manager. DownloadManager* observed_download_manager_; }; friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; friend class DeleteTask<DownloadManager>; friend class OtherDownloadManagerObserver; ~DownloadManager(); // Called on the download thread to check whether the suggested file path // exists. We don't check if the file exists on the UI thread to avoid UI // stalls from interacting with the file system. void CheckIfSuggestedPathExists(DownloadCreateInfo* info, const FilePath& default_path); // Called on the UI thread once the DownloadManager has determined whether the // suggested file path exists. void OnPathExistenceAvailable(DownloadCreateInfo* info); // Called back after a target path for the file to be downloaded to has been // determined, either automatically based on the suggested file name, or by // the user in a Save As dialog box. void AttachDownloadItem(DownloadCreateInfo* info); // Download cancel helper function. void DownloadCancelledInternal(int download_id, int render_process_id, int request_id); // All data has been downloaded. // |hash| is sha256 hash for the downloaded file. It is empty when the hash // is not available. void OnAllDataSaved(int32 download_id, int64 size, const std::string& hash); // An error occurred in the download. void OnDownloadError(int32 download_id, int64 size, int os_error); // Updates the app icon about the overall download progress. void UpdateAppIcon(); // Makes the ResourceDispatcherHost pause/un-pause a download request. // Called on the IO thread. void PauseDownloadRequest(ResourceDispatcherHost* rdh, int render_process_id, int request_id, bool pause); // Inform observers that the model has changed. void NotifyModelChanged(); DownloadItem* GetDownloadItem(int id); // Debugging routine to confirm relationship between below // containers; no-op if NDEBUG. void AssertContainersConsistent() const; // |downloads_| is the owning set for all downloads known to the // DownloadManager. This includes downloads started by the user in // this session, downloads initialized from the history system, and // "save page as" downloads. All other DownloadItem containers in // the DownloadManager are maps; they do not own the DownloadItems. // Note that this is the only place (with any functional implications; // see save_page_as_downloads_ below) that "save page as" downloads are // kept, as the DownloadManager's only job is to hold onto those // until destruction. // // |history_downloads_| is map of all downloads in this profile. The key // is the handle returned by the history system, which is unique // across sessions. // // |active_downloads_| is a map of all downloads that are currently being // processed. The key is the ID assigned by the ResourceDispatcherHost, // which is unique for the current session. // // |in_progress_| is a map of all downloads that are in progress and that have // not yet received a valid history handle. The key is the ID assigned by the // ResourceDispatcherHost, which is unique for the current session. // // |save_page_as_downloads_| (if defined) is a collection of all the // downloads the "save page as" system has given to us to hold onto // until we are destroyed. It is only used for debugging. // // When a download is created through a user action, the corresponding // DownloadItem* is placed in |active_downloads_| and remains there until the // download is in a terminal state (COMPLETE or CANCELLED). It is also // placed in |in_progress_| and remains there until it has received a // valid handle from the history system. Once it has a valid handle, the // DownloadItem* is placed in the |history_downloads_| map. When the // download reaches a terminal state, it is removed from |in_progress_|. // Downloads from past sessions read from a persisted state from the // history system are placed directly into |history_downloads_| since // they have valid handles in the history system. typedef std::set<DownloadItem*> DownloadSet; typedef base::hash_map<int64, DownloadItem*> DownloadMap; DownloadSet downloads_; DownloadMap history_downloads_; DownloadMap in_progress_; DownloadMap active_downloads_; #if !defined(NDEBUG) DownloadSet save_page_as_downloads_; #endif // True if the download manager has been initialized and requires a shutdown. bool shutdown_needed_; // Observers that want to be notified of changes to the set of downloads. ObserverList<Observer> observers_; // The current active profile. Profile* profile_; scoped_refptr<net::URLRequestContextGetter> request_context_getter_; scoped_ptr<DownloadHistory> download_history_; scoped_ptr<DownloadPrefs> download_prefs_; // Non-owning pointer for handling file writing on the download_thread_. DownloadFileManager* file_manager_; // Non-owning pointer for updating the download status. base::WeakPtr<DownloadStatusUpdater> status_updater_; // The user's last choice for download directory. This is only used when the // user wants us to prompt for a save location for each download. FilePath last_download_path_; // The "Save As" dialog box used to ask the user where a file should be // saved. scoped_refptr<SelectFileDialog> select_file_dialog_; scoped_ptr<OtherDownloadManagerObserver> other_download_manager_observer_; DISALLOW_COPY_AND_ASSIGN(DownloadManager); }; #endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_H_