• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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