| // 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. |
| // |
| // Objects that handle file operations for saving files, on the file thread. |
| // |
| // The SaveFileManager owns a set of SaveFile objects, each of which connects |
| // with a SaveItem object which belongs to one SavePackage and runs on the file |
| // thread for saving data in order to avoid disk activity on either network IO |
| // thread or the UI thread. It coordinates the notifications from the network |
| // and UI. |
| // |
| // The SaveFileManager itself is a singleton object owned by the |
| // ResourceDispatcherHost. |
| // |
| // The data sent to SaveFileManager have 2 sources, one is from |
| // ResourceDispatcherHost, run in network IO thread, the all sub-resources |
| // and save-only-HTML pages will be got from network IO. The second is from |
| // render process, those html pages which are serialized from DOM will be |
| // composed in render process and encoded to its original encoding, then sent |
| // to UI loop in browser process, then UI loop will dispatch the data to |
| // SaveFileManager on the file thread. SaveFileManager will directly |
| // call SaveFile's method to persist data. |
| // |
| // A typical saving job operation involves multiple threads: |
| // |
| // Updating an in progress save file |
| // io_thread |
| // |----> data from net ---->| |
| // | |
| // | |
| // |----> data from ---->| | |
| // | render process | | |
| // ui_thread | | |
| // file_thread (writes to disk) |
| // |----> stats ---->| |
| // ui_thread (feedback for user) |
| // |
| // |
| // 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 |
| // ui_thread (user close tab) for saving) |
| // |----> cancel command ---->| |
| // Render process(stop serializing DOM and sending |
| // data) |
| // |
| // |
| // The SaveFileManager tracks saving requests, mapping from a save ID |
| // (unique integer created in the IO thread) to the SavePackage for the |
| // tab where the saving job was initiated. In the event of a tab closure |
| // during saving, the SavePackage will notice the SaveFileManage to |
| // cancel all SaveFile job. |
| |
| #ifndef CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__ |
| #define CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__ |
| #pragma once |
| |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "base/hash_tables.h" |
| #include "base/memory/ref_counted.h" |
| #include "chrome/browser/download/save_types.h" |
| |
| namespace net { |
| class IOBuffer; |
| } |
| class FilePath; |
| class GURL; |
| class SaveFile; |
| class SavePackage; |
| class ResourceDispatcherHost; |
| class Task; |
| |
| namespace net { |
| class URLRequestContextGetter; |
| } |
| |
| class SaveFileManager |
| : public base::RefCountedThreadSafe<SaveFileManager> { |
| public: |
| explicit SaveFileManager(ResourceDispatcherHost* rdh); |
| |
| // Lifetime management. |
| void Shutdown(); |
| |
| // Called on the IO thread |
| int GetNextId(); |
| |
| // Save the specified URL. Called on the UI thread and forwarded to the |
| // ResourceDispatcherHost on the IO thread. |
| void SaveURL(const GURL& url, |
| const GURL& referrer, |
| int render_process_host_id, |
| int render_view_id, |
| SaveFileCreateInfo::SaveFileSource save_source, |
| const FilePath& file_full_path, |
| net::URLRequestContextGetter* request_context_getter, |
| SavePackage* save_package); |
| |
| // Notifications sent from the IO thread and run on the file thread: |
| void StartSave(SaveFileCreateInfo* info); |
| void UpdateSaveProgress(int save_id, net::IOBuffer* data, int size); |
| void SaveFinished(int save_id, |
| const GURL& save_url, |
| int render_process_id, |
| bool is_success); |
| |
| // Notifications sent from the UI thread and run on the file thread. |
| // Cancel a SaveFile instance which has specified save id. |
| void CancelSave(int save_id); |
| |
| // Called on the UI thread to remove a save package from SaveFileManager's |
| // tracking map. |
| void RemoveSaveFile(int save_id, const GURL& save_url, |
| SavePackage* package); |
| |
| #if !defined(OS_MACOSX) |
| // Handler for shell operations sent from the UI to the file thread. Mac OS X |
| // requires opening downloads on the UI thread, so it does not use this |
| // method. |
| void OnShowSavedFileInShell(const FilePath full_path); |
| #endif |
| |
| // Helper function for deleting specified file. |
| void DeleteDirectoryOrFile(const FilePath& full_path, bool is_dir); |
| |
| // Runs on file thread to save a file by copying from file system when |
| // original url is using file scheme. |
| void SaveLocalFile(const GURL& original_file_url, |
| int save_id, |
| int render_process_id); |
| |
| // Renames all the successfully saved files. |
| // |final_names| points to a vector which contains pairs of save ids and |
| // final names of successfully saved files. |
| void RenameAllFiles( |
| const FinalNameList& final_names, |
| const FilePath& resource_dir, |
| int render_process_id, |
| int render_view_id, |
| int save_package_id); |
| |
| // When the user cancels the saving, we need to remove all remaining saved |
| // files of this page saving job from save_file_map_. |
| void RemoveSavedFileFromFileMap(const SaveIDList & save_ids); |
| |
| private: |
| friend class base::RefCountedThreadSafe<SaveFileManager>; |
| |
| ~SaveFileManager(); |
| |
| // A cleanup helper that runs on the file thread. |
| void OnShutdown(); |
| |
| // Called only on UI thread to get the SavePackage for a tab's profile. |
| static SavePackage* GetSavePackageFromRenderIds(int render_process_id, |
| int review_view_id); |
| |
| // Register a starting request. Associate the save URL with a |
| // SavePackage for further matching. |
| void RegisterStartingRequest(const GURL& save_url, |
| SavePackage* save_package); |
| // Unregister a start request according save URL, disassociate |
| // the save URL and SavePackage. |
| SavePackage* UnregisterStartingRequest(const GURL& save_url, |
| int tab_id); |
| |
| // Look up the SavePackage according to save id. |
| SavePackage* LookupPackage(int save_id); |
| |
| // Called only on the file thread. |
| // Look up one in-progress saving item according to save id. |
| SaveFile* LookupSaveFile(int save_id); |
| |
| // Help function for sending notification of canceling specific request. |
| void SendCancelRequest(int save_id); |
| |
| // Notifications sent from the file thread and run on the UI thread. |
| |
| // Lookup the SaveManager for this TabContents' saving profile and inform it |
| // the saving job has been started. |
| void OnStartSave(const SaveFileCreateInfo* info); |
| // Update the SavePackage with the current state of a started saving job. |
| // If the SavePackage for this saving job is gone, cancel the request. |
| void OnUpdateSaveProgress(int save_id, |
| int64 bytes_so_far, |
| bool write_success); |
| // Update the SavePackage with the finish state, and remove the request |
| // tracking entries. |
| void OnSaveFinished(int save_id, int64 bytes_so_far, bool is_success); |
| // For those requests that do not have valid save id, use |
| // map:(url, SavePackage) to find the request and remove it. |
| void OnErrorFinished(const GURL& save_url, int tab_id); |
| // Notifies SavePackage that the whole page saving job is finished. |
| void OnFinishSavePageJob(int render_process_id, |
| int render_view_id, |
| int save_package_id); |
| |
| // Notifications sent from the UI thread and run on the file thread. |
| |
| // Deletes a specified file on the file thread. |
| void OnDeleteDirectoryOrFile(const FilePath& full_path, bool is_dir); |
| |
| // Notifications sent from the UI thread and run on the IO thread |
| |
| // Initiates a request for URL to be saved. |
| void OnSaveURL(const GURL& url, |
| const GURL& referrer, |
| int render_process_host_id, |
| int render_view_id, |
| net::URLRequestContextGetter* request_context_getter); |
| // Handler for a notification sent to the IO thread for generating save id. |
| void OnRequireSaveJobFromOtherSource(SaveFileCreateInfo* info); |
| // Call ResourceDispatcherHost's CancelRequest method to execute cancel |
| // action in the IO thread. |
| void ExecuteCancelSaveRequest(int render_process_id, int request_id); |
| |
| // Unique ID for the next SaveFile object. |
| int next_id_; |
| |
| // A map of all saving jobs by using save id. |
| typedef base::hash_map<int, SaveFile*> SaveFileMap; |
| SaveFileMap save_file_map_; |
| |
| ResourceDispatcherHost* resource_dispatcher_host_; |
| |
| // Tracks which SavePackage to send data to, called only on UI thread. |
| // SavePackageMap maps save IDs to their SavePackage. |
| typedef base::hash_map<int, SavePackage*> SavePackageMap; |
| SavePackageMap packages_; |
| |
| // There is a gap between after calling SaveURL() and before calling |
| // StartSave(). In this gap, each request does not have save id for tracking. |
| // But sometimes users might want to stop saving job or ResourceDispatcherHost |
| // calls SaveFinished with save id -1 for network error. We name the requests |
| // as starting requests. For tracking those starting requests, we need to |
| // have some data structure. |
| // First we use a hashmap to map the request URL to SavePackage, then we |
| // use a hashmap to map the tab id (we actually use render_process_id) to the |
| // hashmap since it is possible to save same URL in different tab at |
| // same time. |
| typedef base::hash_map<std::string, SavePackage*> StartingRequestsMap; |
| typedef base::hash_map<int, StartingRequestsMap> TabToStartingRequestsMap; |
| TabToStartingRequestsMap tab_starting_requests_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SaveFileManager); |
| }; |
| |
| #endif // CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__ |