1 // Copyright (c) 2012 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 // ResourceDispatcherHostImpl. 15 // 16 // The data sent to SaveFileManager have 2 sources, one is from 17 // ResourceDispatcherHostImpl, 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 contents) 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 (unique 53 // integer created in the IO thread) to the SavePackage for the contents where 54 // the saving job was initiated. In the event of a contents closure during 55 // saving, the SavePackage will notify the SaveFileManage to cancel all SaveFile 56 // jobs. 57 58 #ifndef CONTENT_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H_ 59 #define CONTENT_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H_ 60 61 #include <string> 62 63 #include "base/basictypes.h" 64 #include "base/containers/hash_tables.h" 65 #include "base/memory/ref_counted.h" 66 #include "content/browser/download/save_types.h" 67 #include "content/common/content_export.h" 68 69 class GURL; 70 71 namespace base { 72 class FilePath; 73 } 74 75 namespace net { 76 class IOBuffer; 77 } 78 79 namespace content { 80 class ResourceContext; 81 class SaveFile; 82 class SavePackage; 83 struct Referrer; 84 85 class SaveFileManager : public base::RefCountedThreadSafe<SaveFileManager> { 86 public: 87 SaveFileManager(); 88 89 // Lifetime management. 90 CONTENT_EXPORT void Shutdown(); 91 92 // Called on the IO thread. This generates unique IDs for 93 // SaveFileResourceHandler objects (there's one per file in a SavePackage). 94 // Note that this is different from the SavePackage's id. 95 int GetNextId(); 96 97 // Save the specified URL. Called on the UI thread and forwarded to the 98 // ResourceDispatcherHostImpl on the IO thread. 99 void SaveURL(const GURL& url, 100 const Referrer& referrer, 101 int render_process_host_id, 102 int render_view_id, 103 SaveFileCreateInfo::SaveFileSource save_source, 104 const base::FilePath& file_full_path, 105 ResourceContext* context, 106 SavePackage* save_package); 107 108 // Notifications sent from the IO thread and run on the file thread: 109 void StartSave(SaveFileCreateInfo* info); 110 void UpdateSaveProgress(int save_id, net::IOBuffer* data, int size); 111 void SaveFinished(int save_id, 112 const GURL& save_url, 113 int render_process_id, 114 bool is_success); 115 116 // Notifications sent from the UI thread and run on the file thread. 117 // Cancel a SaveFile instance which has specified save id. 118 void CancelSave(int save_id); 119 120 // Called on the UI thread to remove a save package from SaveFileManager's 121 // tracking map. 122 void RemoveSaveFile(int save_id, const GURL& save_url, 123 SavePackage* package); 124 125 // Helper function for deleting specified file. 126 void DeleteDirectoryOrFile(const base::FilePath& full_path, bool is_dir); 127 128 // Runs on file thread to save a file by copying from file system when 129 // original url is using file scheme. 130 void SaveLocalFile(const GURL& original_file_url, 131 int save_id, 132 int render_process_id); 133 134 // Renames all the successfully saved files. 135 // |final_names| points to a vector which contains pairs of save ids and 136 // final names of successfully saved files. 137 void RenameAllFiles( 138 const FinalNameList& final_names, 139 const base::FilePath& resource_dir, 140 int render_process_id, 141 int render_view_id, 142 int save_package_id); 143 144 // When the user cancels the saving, we need to remove all remaining saved 145 // files of this page saving job from save_file_map_. 146 void RemoveSavedFileFromFileMap(const SaveIDList & save_ids); 147 148 private: 149 friend class base::RefCountedThreadSafe<SaveFileManager>; 150 151 ~SaveFileManager(); 152 153 // A cleanup helper that runs on the file thread. 154 void OnShutdown(); 155 156 // Called only on UI thread to get the SavePackage for a contents's browser 157 // context. 158 static SavePackage* GetSavePackageFromRenderIds(int render_process_id, 159 int review_view_id); 160 161 // Register a starting request. Associate the save URL with a 162 // SavePackage for further matching. 163 void RegisterStartingRequest(const GURL& save_url, 164 SavePackage* save_package); 165 // Unregister a start request according save URL, disassociate 166 // the save URL and SavePackage. 167 SavePackage* UnregisterStartingRequest(const GURL& save_url, 168 int contents_id); 169 170 // Look up the SavePackage according to save id. 171 SavePackage* LookupPackage(int save_id); 172 173 // Called only on the file thread. 174 // Look up one in-progress saving item according to save id. 175 SaveFile* LookupSaveFile(int save_id); 176 177 // Help function for sending notification of canceling specific request. 178 void SendCancelRequest(int save_id); 179 180 // Notifications sent from the file thread and run on the UI thread. 181 182 // Lookup the SaveManager for this WebContents' saving browser context and 183 // inform it the saving job has been started. 184 void OnStartSave(const SaveFileCreateInfo* info); 185 // Update the SavePackage with the current state of a started saving job. 186 // If the SavePackage for this saving job is gone, cancel the request. 187 void OnUpdateSaveProgress(int save_id, 188 int64 bytes_so_far, 189 bool write_success); 190 // Update the SavePackage with the finish state, and remove the request 191 // tracking entries. 192 void OnSaveFinished(int save_id, int64 bytes_so_far, bool is_success); 193 // For those requests that do not have valid save id, use 194 // map:(url, SavePackage) to find the request and remove it. 195 void OnErrorFinished(const GURL& save_url, int contents_id); 196 // Notifies SavePackage that the whole page saving job is finished. 197 void OnFinishSavePageJob(int render_process_id, 198 int render_view_id, 199 int save_package_id); 200 201 // Notifications sent from the UI thread and run on the file thread. 202 203 // Deletes a specified file on the file thread. 204 void OnDeleteDirectoryOrFile(const base::FilePath& full_path, bool is_dir); 205 206 // Notifications sent from the UI thread and run on the IO thread 207 208 // Initiates a request for URL to be saved. 209 void OnSaveURL(const GURL& url, 210 const Referrer& referrer, 211 int render_process_host_id, 212 int render_view_id, 213 ResourceContext* context); 214 // Handler for a notification sent to the IO thread for generating save id. 215 void OnRequireSaveJobFromOtherSource(SaveFileCreateInfo* info); 216 // Call ResourceDispatcherHostImpl's CancelRequest method to execute cancel 217 // action in the IO thread. 218 void ExecuteCancelSaveRequest(int render_process_id, int request_id); 219 220 // Unique ID for the next SaveFile object. 221 int next_id_; 222 223 // A map of all saving jobs by using save id. 224 typedef base::hash_map<int, SaveFile*> SaveFileMap; 225 SaveFileMap save_file_map_; 226 227 // Tracks which SavePackage to send data to, called only on UI thread. 228 // SavePackageMap maps save IDs to their SavePackage. 229 typedef base::hash_map<int, SavePackage*> SavePackageMap; 230 SavePackageMap packages_; 231 232 // There is a gap between after calling SaveURL() and before calling 233 // StartSave(). In this gap, each request does not have save id for tracking. 234 // But sometimes users might want to stop saving job or ResourceDispatcherHost 235 // calls SaveFinished with save id -1 for network error. We name the requests 236 // as starting requests. For tracking those starting requests, we need to 237 // have some data structure. 238 // First we use a hashmap to map the request URL to SavePackage, then we use a 239 // hashmap to map the contents id (we actually use render_process_id) to the 240 // hashmap since it is possible to save the same URL in different contents at 241 // same time. 242 typedef base::hash_map<std::string, SavePackage*> StartingRequestsMap; 243 typedef base::hash_map<int, StartingRequestsMap> 244 ContentsToStartingRequestsMap; 245 ContentsToStartingRequestsMap contents_starting_requests_; 246 247 DISALLOW_COPY_AND_ASSIGN(SaveFileManager); 248 }; 249 250 } // namespace content 251 252 #endif // CONTENT_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H_ 253