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 69class GURL; 70 71namespace base { 72class FilePath; 73} 74 75namespace net { 76class IOBuffer; 77} 78 79namespace content { 80class ResourceContext; 81class SaveFile; 82class SavePackage; 83struct Referrer; 84 85class 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