| // Copyright (c) 2006-2009 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. |
| // |
| // 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 |
| // 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_ |
| |
| #include "build/build_config.h" |
| |
| #include <string> |
| #include <map> |
| #include <set> |
| #include <vector> |
| |
| #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 "chrome/browser/cancelable_request.h" |
| #include "chrome/browser/history/download_types.h" |
| #include "chrome/browser/history/history.h" |
| #include "chrome/browser/shell_dialogs.h" |
| #include "chrome/common/pref_member.h" |
| |
| class DownloadFileManager; |
| class DownloadItemView; |
| class DownloadManager; |
| class GURL; |
| class MessageLoop; |
| class PrefService; |
| class Profile; |
| class ResourceDispatcherHost; |
| class URLRequestContext; |
| class WebContents; |
| |
| 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 opened. |
| virtual void OnDownloadOpened(DownloadItem* download) = 0; |
| }; |
| |
| // Constructing from persistent store: |
| DownloadItem(const DownloadCreateInfo& info); |
| |
| // Constructing from user action: |
| DownloadItem(int32 download_id, |
| const FilePath& path, |
| int path_uniquifier, |
| const GURL& url, |
| const FilePath& original_name, |
| const base::Time start_time, |
| int64 download_size, |
| int render_process_id, |
| int request_id, |
| bool is_dangerous); |
| |
| ~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 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_; } |
| 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; |
| } |
| FilePath original_name() const { return original_name_; } |
| void set_original_name(const FilePath& name) { original_name_ = name; } |
| |
| // 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_; |
| |
| // 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_; |
| |
| // 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_; |
| |
| DISALLOW_EVIL_CONSTRUCTORS(DownloadItem); |
| }; |
| |
| |
| // DownloadManager ------------------------------------------------------------- |
| |
| // Browser's download manager: manages all downloads and destination view. |
| class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>, |
| public SelectFileDialog::Listener { |
| // For testing. |
| friend class DownloadManagerTest; |
| |
| public: |
| DownloadManager(); |
| ~DownloadManager(); |
| |
| static void RegisterUserPrefs(PrefService* prefs); |
| |
| // 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; |
| |
| // A callback once the DownloadManager has retrieved the requested set of |
| // downloads. The DownloadManagerObserver must copy the vector, but does not |
| // own the individual DownloadItems, when this call is made. |
| virtual void SetDownloads(std::vector<DownloadItem*>& downloads) = 0; |
| }; |
| |
| // Public API |
| |
| // Begin a search for all downloads matching 'search_text'. If 'search_text' |
| // is empty, return all known downloads. The results are returned in the |
| // 'SetDownloads' observer callback. |
| void GetDownloads(Observer* observer, |
| const std::wstring& search_text); |
| |
| // Returns true if initialized properly. |
| bool Init(Profile* profile); |
| |
| // Schedule a query of the history service to retrieve all downloads. |
| void QueryHistoryForDownloads(); |
| |
| // Notifications sent from the download thread to the UI thread |
| void StartDownload(DownloadCreateInfo* info); |
| void UpdateDownload(int32 download_id, int64 size); |
| void DownloadFinished(int32 download_id, int64 size); |
| |
| // Helper method for cancelling the network request associated with a |
| // download. |
| static void CancelDownloadRequest(int render_process_id, int request_id); |
| |
| // 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); |
| |
| // Called when the download is renamed to its final name. |
| void DownloadRenamedToFinalName(int download_id, const FilePath& full_path); |
| |
| // 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(); |
| |
| // 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, |
| WebContents* web_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); |
| void OnSearchComplete(HistoryService::Handle handle, |
| std::vector<int64>* results); |
| |
| // Opens a download. For Chrome extensions call |
| // ExtensionsServices::InstallExtension, for everything else call |
| // OpenDownloadInShell. |
| void OpenDownload(const DownloadItem* download, |
| gfx::NativeView parent_window); |
| |
| // Show a download via the Windows shell. |
| void ShowDownloadInShell(const DownloadItem* download); |
| |
| // The number of in progress (including paused) downloads. |
| int in_progress_count() const { |
| return static_cast<int>(in_progress_.size()); |
| } |
| |
| FilePath download_path() { |
| return FilePath::FromWStringHack(*download_path_); |
| } |
| |
| // Clears the last download path, used to initialize "save as" dialogs. |
| void ClearLastDownloadPath(); |
| |
| // Registers this file extension for automatic opening upon download |
| // completion if 'open' is true, or prevents the extension from automatic |
| // opening if 'open' is false. |
| void OpenFilesOfExtension(const FilePath::StringType& extension, bool open); |
| |
| // Tests if a file type should be opened automatically. |
| bool ShouldOpenFileExtension(const FilePath::StringType& extension); |
| |
| // Tests if we think the server means for this mime_type to be executable. |
| static bool IsExecutableMimeType(const std::string& mime_type); |
| |
| // Tests if a file type is considered executable. |
| bool IsExecutable(const FilePath::StringType& extension); |
| |
| // Resets the automatic open preference. |
| void ResetAutoOpenFiles(); |
| |
| // Returns true if there are automatic handlers registered for any file |
| // types. |
| bool HasAutoOpenFileTypesRegistered() const; |
| |
| // Overridden from SelectFileDialog::Listener: |
| virtual void FileSelected(const FilePath& path, int index, void* params); |
| virtual void FileSelectionCanceled(void* params); |
| |
| // Deletes the specified path on the file thread. |
| void DeleteDownload(const FilePath& path); |
| |
| // Called when the user has validated the donwload of a dangerous file. |
| void DangerousDownloadValidated(DownloadItem* download); |
| |
| // Used to make sure we have a safe file extension and filename for a |
| // download. |file_name| can either be just the file name or it can be a |
| // full path to a file. |
| void GenerateSafeFilename(const std::string& mime_type, |
| FilePath* file_name); |
| |
| private: |
| // Opens a download via the Windows shell. |
| void OpenDownloadInShell(const DownloadItem* download, |
| gfx::NativeView parent_window); |
| |
| // Opens downloaded Chrome extension file (*.crx). |
| void OpenChromeExtension(const FilePath& full_path); |
| |
| // Shutdown the download manager. This call is needed only after Init. |
| void Shutdown(); |
| |
| // 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); |
| |
| // 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 ContinueStartDownload(DownloadCreateInfo* info, |
| const FilePath& target_path); |
| |
| // Update the history service for a particular download. |
| void UpdateHistoryForDownload(DownloadItem* download); |
| void RemoveDownloadFromHistory(DownloadItem* download); |
| void RemoveDownloadsFromHistoryBetween(const base::Time remove_begin, |
| const base::Time remove_before); |
| |
| // Create an extension based on the file name and mime type. |
| void GenerateExtension(const FilePath& file_name, |
| const std::string& mime_type, |
| FilePath::StringType* generated_extension); |
| |
| // Create a file name based on the response from the server. |
| void GenerateFilename(DownloadCreateInfo* info, FilePath* generated_name); |
| |
| // Persist the automatic opening preference. |
| void SaveAutoOpens(); |
| |
| // Runs the network cancel on the IO thread. |
| static void OnCancelDownloadRequest(ResourceDispatcherHost* rdh, |
| int render_process_id, |
| int request_id); |
| |
| // Runs the pause on the IO thread. |
| static void OnPauseDownloadRequest(ResourceDispatcherHost* rdh, |
| int render_process_id, |
| int request_id, |
| bool pause); |
| |
| // Performs the last steps required when a download has been completed. |
| // It is necessary to break down the flow when a download is finished as |
| // dangerous downloads are downloaded to temporary files that need to be |
| // renamed on the file thread first. |
| // Invoked on the UI thread. |
| void ContinueDownloadFinished(DownloadItem* download); |
| |
| // Renames a finished dangerous download from its temporary file name to its |
| // real file name. |
| // Invoked on the file thread. |
| void ProceedWithFinishedDangerousDownload(int64 download_handle, |
| const FilePath& path, |
| const FilePath& original_name); |
| |
| // Invoked on the UI thread when a dangerous downloaded file has been renamed. |
| void DangerousDownloadRenamed(int64 download_handle, |
| bool success, |
| const FilePath& new_path, |
| int new_path_uniquifier); |
| |
| // Checks whether a file represents a risk if downloaded. |
| bool IsDangerous(const FilePath& file_name); |
| |
| // Changes the paths and file name of the specified |download|, propagating |
| // the change to the history system. |
| void RenameDownload(DownloadItem* download, const FilePath& new_path); |
| |
| // 'downloads_' is map of all downloads in this profile. The key is the handle |
| // returned by the history system, which is unique across sessions. This map |
| // owns all the DownloadItems once they have been created in the history |
| // system. |
| // |
| // '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. This map |
| // does not own the DownloadItems. |
| // |
| // 'dangerous_finished_' is a map of dangerous download that have finished |
| // but were not yet approved by the user. Similarly to in_progress_, the key |
| // is the ID assigned by the ResourceDispatcherHost and the map does not own |
| // the DownloadItems. It is used on shutdown to delete completed downloads |
| // that have not been approved. |
| // |
| // When a download is created through a user action, the corresponding |
| // DownloadItem* is 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 'downloads_' map. When the |
| // download is complete, it is removed from 'in_progress_'. Downloads from |
| // past sessions read from a persisted state from the history system are |
| // placed directly into 'downloads_' since they have valid handles in the |
| // history system. |
| typedef base::hash_map<int64, DownloadItem*> DownloadMap; |
| DownloadMap downloads_; |
| DownloadMap in_progress_; |
| DownloadMap dangerous_finished_; |
| |
| // 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<URLRequestContext> request_context_; |
| |
| // Used for history service request management. |
| CancelableRequestConsumerTSimple<Observer*> cancelable_consumer_; |
| |
| // Non-owning pointer for handling file writing on the download_thread_. |
| DownloadFileManager* file_manager_; |
| |
| // A pointer to the main UI loop. |
| MessageLoop* ui_loop_; |
| |
| // A pointer to the file thread's loop. The file thread lives longer than |
| // the DownloadManager, so this is safe to cache. |
| MessageLoop* file_loop_; |
| |
| // User preferences |
| BooleanPrefMember prompt_for_download_; |
| StringPrefMember download_path_; |
| |
| // 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_; |
| |
| // Set of file extensions to open at download completion. |
| std::set<FilePath::StringType> auto_open_; |
| |
| // Set of file extensions that are executables and shouldn't be auto opened. |
| std::set<std::string> exe_types_; |
| |
| // Keep track of downloads that are completed before the user selects the |
| // destination, so that observers are appropriately notified of completion |
| // after this determination is made. |
| // The map is of download_id->remaining size (bytes), both of which are |
| // required when calling DownloadFinished. |
| typedef std::map<int32, int64> PendingFinishedMap; |
| PendingFinishedMap pending_finished_downloads_; |
| |
| // The "Save As" dialog box used to ask the user where a file should be |
| // saved. |
| scoped_refptr<SelectFileDialog> select_file_dialog_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DownloadManager); |
| }; |
| |
| #endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_H_ |