1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 // 5 // Objects that handle file operations for saving files, on the file thread. 6 // 7 // The SaveFileManager owns a set of SaveFile objects, each of which connects 8 // with a SaveItem object which belongs to one SavePackage and runs on the file 9 // thread for saving data in order to avoid disk activity on either network IO 10 // thread or the UI thread. It coordinates the notifications from the network 11 // and UI. 12 // 13 // The SaveFileManager itself is a singleton object owned by the 14 // ResourceDispatcherHost. 15 // 16 // The data sent to SaveFileManager have 2 sources, one is from 17 // ResourceDispatcherHost, run in network IO thread, the all sub-resources 18 // and save-only-HTML pages will be got from network IO. The second is from 19 // render process, those html pages which are serialized from DOM will be 20 // composed in render process and encoded to its original encoding, then sent 21 // to UI loop in browser process, then UI loop will dispatch the data to 22 // SaveFileManager on the file thread. SaveFileManager will directly 23 // call SaveFile's method to persist data. 24 // 25 // A typical saving job operation involves multiple threads: 26 // 27 // Updating an in progress save file 28 // io_thread 29 // |----> data from net ---->| 30 // | 31 // | 32 // |----> data from ---->| | 33 // | render process | | 34 // ui_thread | | 35 // file_thread (writes to disk) 36 // |----> stats ---->| 37 // ui_thread (feedback for user) 38 // 39 // 40 // Cancel operations perform the inverse order when triggered by a user action: 41 // ui_thread (user click) 42 // |----> cancel command ---->| 43 // | | file_thread (close file) 44 // | |---------------------> cancel command ---->| 45 // | io_thread (stops net IO 46 // ui_thread (user close tab) for saving) 47 // |----> cancel command ---->| 48 // Render process(stop serializing DOM and sending 49 // data) 50 // 51 // 52 // The SaveFileManager tracks saving requests, mapping from a save ID 53 // (unique integer created in the IO thread) to the SavePackage for the 54 // tab where the saving job was initiated. In the event of a tab closure 55 // during saving, the SavePackage will notice the SaveFileManage to 56 // cancel all SaveFile job. 57 58 #ifndef CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__ 59 #define CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__ 60 #pragma once 61 62 #include <string> 63 64 #include "base/basictypes.h" 65 #include "base/hash_tables.h" 66 #include "base/memory/ref_counted.h" 67 #include "chrome/browser/download/save_types.h" 68 69 namespace net { 70 class IOBuffer; 71 } 72 class FilePath; 73 class GURL; 74 class SaveFile; 75 class SavePackage; 76 class ResourceDispatcherHost; 77 class Task; 78 79 namespace net { 80 class URLRequestContextGetter; 81 } 82 83 class SaveFileManager 84 : public base::RefCountedThreadSafe<SaveFileManager> { 85 public: 86 explicit SaveFileManager(ResourceDispatcherHost* rdh); 87 88 // Lifetime management. 89 void Shutdown(); 90 91 // Called on the IO thread 92 int GetNextId(); 93 94 // Save the specified URL. Called on the UI thread and forwarded to the 95 // ResourceDispatcherHost on the IO thread. 96 void SaveURL(const GURL& url, 97 const GURL& referrer, 98 int render_process_host_id, 99 int render_view_id, 100 SaveFileCreateInfo::SaveFileSource save_source, 101 const FilePath& file_full_path, 102 net::URLRequestContextGetter* request_context_getter, 103 SavePackage* save_package); 104 105 // Notifications sent from the IO thread and run on the file thread: 106 void StartSave(SaveFileCreateInfo* info); 107 void UpdateSaveProgress(int save_id, net::IOBuffer* data, int size); 108 void SaveFinished(int save_id, 109 const GURL& save_url, 110 int render_process_id, 111 bool is_success); 112 113 // Notifications sent from the UI thread and run on the file thread. 114 // Cancel a SaveFile instance which has specified save id. 115 void CancelSave(int save_id); 116 117 // Called on the UI thread to remove a save package from SaveFileManager's 118 // tracking map. 119 void RemoveSaveFile(int save_id, const GURL& save_url, 120 SavePackage* package); 121 122 #if !defined(OS_MACOSX) 123 // Handler for shell operations sent from the UI to the file thread. Mac OS X 124 // requires opening downloads on the UI thread, so it does not use this 125 // method. 126 void OnShowSavedFileInShell(const FilePath full_path); 127 #endif 128 129 // Helper function for deleting specified file. 130 void DeleteDirectoryOrFile(const FilePath& full_path, bool is_dir); 131 132 // Runs on file thread to save a file by copying from file system when 133 // original url is using file scheme. 134 void SaveLocalFile(const GURL& original_file_url, 135 int save_id, 136 int render_process_id); 137 138 // Renames all the successfully saved files. 139 // |final_names| points to a vector which contains pairs of save ids and 140 // final names of successfully saved files. 141 void RenameAllFiles( 142 const FinalNameList& final_names, 143 const FilePath& resource_dir, 144 int render_process_id, 145 int render_view_id, 146 int save_package_id); 147 148 // When the user cancels the saving, we need to remove all remaining saved 149 // files of this page saving job from save_file_map_. 150 void RemoveSavedFileFromFileMap(const SaveIDList & save_ids); 151 152 private: 153 friend class base::RefCountedThreadSafe<SaveFileManager>; 154 155 ~SaveFileManager(); 156 157 // A cleanup helper that runs on the file thread. 158 void OnShutdown(); 159 160 // Called only on UI thread to get the SavePackage for a tab's profile. 161 static SavePackage* GetSavePackageFromRenderIds(int render_process_id, 162 int review_view_id); 163 164 // Register a starting request. Associate the save URL with a 165 // SavePackage for further matching. 166 void RegisterStartingRequest(const GURL& save_url, 167 SavePackage* save_package); 168 // Unregister a start request according save URL, disassociate 169 // the save URL and SavePackage. 170 SavePackage* UnregisterStartingRequest(const GURL& save_url, 171 int tab_id); 172 173 // Look up the SavePackage according to save id. 174 SavePackage* LookupPackage(int save_id); 175 176 // Called only on the file thread. 177 // Look up one in-progress saving item according to save id. 178 SaveFile* LookupSaveFile(int save_id); 179 180 // Help function for sending notification of canceling specific request. 181 void SendCancelRequest(int save_id); 182 183 // Notifications sent from the file thread and run on the UI thread. 184 185 // Lookup the SaveManager for this TabContents' saving profile and inform it 186 // the saving job has been started. 187 void OnStartSave(const SaveFileCreateInfo* info); 188 // Update the SavePackage with the current state of a started saving job. 189 // If the SavePackage for this saving job is gone, cancel the request. 190 void OnUpdateSaveProgress(int save_id, 191 int64 bytes_so_far, 192 bool write_success); 193 // Update the SavePackage with the finish state, and remove the request 194 // tracking entries. 195 void OnSaveFinished(int save_id, int64 bytes_so_far, bool is_success); 196 // For those requests that do not have valid save id, use 197 // map:(url, SavePackage) to find the request and remove it. 198 void OnErrorFinished(const GURL& save_url, int tab_id); 199 // Notifies SavePackage that the whole page saving job is finished. 200 void OnFinishSavePageJob(int render_process_id, 201 int render_view_id, 202 int save_package_id); 203 204 // Notifications sent from the UI thread and run on the file thread. 205 206 // Deletes a specified file on the file thread. 207 void OnDeleteDirectoryOrFile(const FilePath& full_path, bool is_dir); 208 209 // Notifications sent from the UI thread and run on the IO thread 210 211 // Initiates a request for URL to be saved. 212 void OnSaveURL(const GURL& url, 213 const GURL& referrer, 214 int render_process_host_id, 215 int render_view_id, 216 net::URLRequestContextGetter* request_context_getter); 217 // Handler for a notification sent to the IO thread for generating save id. 218 void OnRequireSaveJobFromOtherSource(SaveFileCreateInfo* info); 219 // Call ResourceDispatcherHost's CancelRequest method to execute cancel 220 // action in the IO thread. 221 void ExecuteCancelSaveRequest(int render_process_id, int request_id); 222 223 // Unique ID for the next SaveFile object. 224 int next_id_; 225 226 // A map of all saving jobs by using save id. 227 typedef base::hash_map<int, SaveFile*> SaveFileMap; 228 SaveFileMap save_file_map_; 229 230 ResourceDispatcherHost* resource_dispatcher_host_; 231 232 // Tracks which SavePackage to send data to, called only on UI thread. 233 // SavePackageMap maps save IDs to their SavePackage. 234 typedef base::hash_map<int, SavePackage*> SavePackageMap; 235 SavePackageMap packages_; 236 237 // There is a gap between after calling SaveURL() and before calling 238 // StartSave(). In this gap, each request does not have save id for tracking. 239 // But sometimes users might want to stop saving job or ResourceDispatcherHost 240 // calls SaveFinished with save id -1 for network error. We name the requests 241 // as starting requests. For tracking those starting requests, we need to 242 // have some data structure. 243 // First we use a hashmap to map the request URL to SavePackage, then we 244 // use a hashmap to map the tab id (we actually use render_process_id) to the 245 // hashmap since it is possible to save same URL in different tab at 246 // same time. 247 typedef base::hash_map<std::string, SavePackage*> StartingRequestsMap; 248 typedef base::hash_map<int, StartingRequestsMap> TabToStartingRequestsMap; 249 TabToStartingRequestsMap tab_starting_requests_; 250 251 DISALLOW_COPY_AND_ASSIGN(SaveFileManager); 252 }; 253 254 #endif // CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__ 255