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