| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "build/build_config.h" | 5 #include "build/build_config.h" |
| 6 | 6 |
| 7 #include "chrome/browser/download/save_file_manager.h" | 7 #include "chrome/browser/download/save_file_manager.h" |
| 8 | 8 |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 SaveFileManager::SaveFileManager(MessageLoop* ui_loop, | 29 SaveFileManager::SaveFileManager(MessageLoop* ui_loop, |
| 30 MessageLoop* io_loop, | 30 MessageLoop* io_loop, |
| 31 ResourceDispatcherHost* rdh) | 31 ResourceDispatcherHost* rdh) |
| 32 : next_id_(0), | 32 : next_id_(0), |
| 33 ui_loop_(ui_loop), | 33 ui_loop_(ui_loop), |
| 34 io_loop_(io_loop), | 34 io_loop_(io_loop), |
| 35 resource_dispatcher_host_(rdh) { | 35 resource_dispatcher_host_(rdh) { |
| 36 DCHECK(ui_loop_); | 36 DCHECK(ui_loop_); |
| 37 // Need to make sure that we are in UI thread because using g_browser_process | 37 // Need to make sure that we are in UI thread because using g_browser_process |
| 38 // on a non-UI thread can cause crashes during shutdown. | 38 // on a non-UI thread can cause crashes during shutdown. |
| 39 DCHECK(ui_loop_ == MessageLoop::current()); | 39 DCHECK_EQ(ui_loop_, MessageLoop::current()); |
| 40 // Cache the message loop of file thread. | 40 // Cache the message loop of file thread. |
| 41 base::Thread* thread = g_browser_process->file_thread(); | 41 base::Thread* thread = g_browser_process->file_thread(); |
| 42 if (thread) | 42 if (thread) |
| 43 file_loop_ = thread->message_loop(); | 43 file_loop_ = thread->message_loop(); |
| 44 else | 44 else |
| 45 // It could be NULL when it is created in unit test of | 45 // It could be NULL when it is created in unit test of |
| 46 // ResourceDispatcherHost. | 46 // ResourceDispatcherHost. |
| 47 file_loop_ = NULL; | 47 file_loop_ = NULL; |
| 48 DCHECK(resource_dispatcher_host_); | 48 DCHECK(resource_dispatcher_host_); |
| 49 } | 49 } |
| 50 | 50 |
| 51 SaveFileManager::~SaveFileManager() { | 51 SaveFileManager::~SaveFileManager() { |
| 52 // Check for clean shutdown. | 52 // Check for clean shutdown. |
| 53 DCHECK(save_file_map_.empty()); | 53 DCHECK(save_file_map_.empty()); |
| 54 } | 54 } |
| 55 | 55 |
| 56 // Called during the browser shutdown process to clean up any state (open files, | 56 // Called during the browser shutdown process to clean up any state (open files, |
| 57 // timers) that live on the saving thread (file thread). | 57 // timers) that live on the saving thread (file thread). |
| 58 void SaveFileManager::Shutdown() { | 58 void SaveFileManager::Shutdown() { |
| 59 MessageLoop* loop = file_loop(); | 59 MessageLoop* loop = file_loop(); |
| 60 if (loop) { | 60 if (loop) { |
| 61 loop->PostTask(FROM_HERE, | 61 loop->PostTask(FROM_HERE, |
| 62 NewRunnableMethod(this, &SaveFileManager::OnShutdown)); | 62 NewRunnableMethod(this, &SaveFileManager::OnShutdown)); |
| 63 } | 63 } |
| 64 } | 64 } |
| 65 | 65 |
| 66 // Stop file thread operations. | 66 // Stop file thread operations. |
| 67 void SaveFileManager::OnShutdown() { | 67 void SaveFileManager::OnShutdown() { |
| 68 DCHECK(MessageLoop::current() == file_loop()); | 68 DCHECK_EQ(MessageLoop::current(), file_loop()); |
| 69 STLDeleteValues(&save_file_map_); | 69 STLDeleteValues(&save_file_map_); |
| 70 } | 70 } |
| 71 | 71 |
| 72 SaveFile* SaveFileManager::LookupSaveFile(int save_id) { | 72 SaveFile* SaveFileManager::LookupSaveFile(int save_id) { |
| 73 SaveFileMap::iterator it = save_file_map_.find(save_id); | 73 SaveFileMap::iterator it = save_file_map_.find(save_id); |
| 74 return it == save_file_map_.end() ? NULL : it->second; | 74 return it == save_file_map_.end() ? NULL : it->second; |
| 75 } | 75 } |
| 76 | 76 |
| 77 // Called on the IO thread when | 77 // Called on the IO thread when |
| 78 // a) The ResourceDispatcherHost has decided that a request is savable. | 78 // a) The ResourceDispatcherHost has decided that a request is savable. |
| 79 // b) The resource does not come from the network, but we still need a | 79 // b) The resource does not come from the network, but we still need a |
| 80 // save ID for for managing the status of the saving operation. So we | 80 // save ID for for managing the status of the saving operation. So we |
| 81 // file a request from the file thread to the IO thread to generate a | 81 // file a request from the file thread to the IO thread to generate a |
| 82 // unique save ID. | 82 // unique save ID. |
| 83 int SaveFileManager::GetNextId() { | 83 int SaveFileManager::GetNextId() { |
| 84 DCHECK(MessageLoop::current() == io_loop_); | 84 DCHECK_EQ(MessageLoop::current(), io_loop_); |
| 85 return next_id_++; | 85 return next_id_++; |
| 86 } | 86 } |
| 87 | 87 |
| 88 void SaveFileManager::RegisterStartingRequest(const GURL& save_url, | 88 void SaveFileManager::RegisterStartingRequest(const GURL& save_url, |
| 89 SavePackage* save_package) { | 89 SavePackage* save_package) { |
| 90 // Make sure it runs in the UI thread. | 90 // Make sure it runs in the UI thread. |
| 91 DCHECK(MessageLoop::current() == ui_loop_); | 91 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 92 int tab_id = save_package->tab_id(); | 92 int tab_id = save_package->tab_id(); |
| 93 | 93 |
| 94 // Register this starting request. | 94 // Register this starting request. |
| 95 StartingRequestsMap& starting_requests = tab_starting_requests_[tab_id]; | 95 StartingRequestsMap& starting_requests = tab_starting_requests_[tab_id]; |
| 96 bool never_present = starting_requests.insert( | 96 bool never_present = starting_requests.insert( |
| 97 StartingRequestsMap::value_type(save_url.spec(), save_package)).second; | 97 StartingRequestsMap::value_type(save_url.spec(), save_package)).second; |
| 98 DCHECK(never_present); | 98 DCHECK(never_present); |
| 99 } | 99 } |
| 100 | 100 |
| 101 SavePackage* SaveFileManager::UnregisterStartingRequest( | 101 SavePackage* SaveFileManager::UnregisterStartingRequest( |
| 102 const GURL& save_url, int tab_id) { | 102 const GURL& save_url, int tab_id) { |
| 103 // Make sure it runs in UI thread. | 103 // Make sure it runs in UI thread. |
| 104 DCHECK(MessageLoop::current() == ui_loop_); | 104 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 105 | 105 |
| 106 TabToStartingRequestsMap::iterator it = tab_starting_requests_.find(tab_id); | 106 TabToStartingRequestsMap::iterator it = tab_starting_requests_.find(tab_id); |
| 107 if (it != tab_starting_requests_.end()) { | 107 if (it != tab_starting_requests_.end()) { |
| 108 StartingRequestsMap& requests = it->second; | 108 StartingRequestsMap& requests = it->second; |
| 109 StartingRequestsMap::iterator sit = requests.find(save_url.spec()); | 109 StartingRequestsMap::iterator sit = requests.find(save_url.spec()); |
| 110 if (sit == requests.end()) | 110 if (sit == requests.end()) |
| 111 return NULL; | 111 return NULL; |
| 112 | 112 |
| 113 // Found, erase it from starting list and return SavePackage. | 113 // Found, erase it from starting list and return SavePackage. |
| 114 SavePackage* save_package = sit->second; | 114 SavePackage* save_package = sit->second; |
| 115 requests.erase(sit); | 115 requests.erase(sit); |
| 116 // If there is no element in requests, remove it | 116 // If there is no element in requests, remove it |
| 117 if (requests.empty()) | 117 if (requests.empty()) |
| 118 tab_starting_requests_.erase(it); | 118 tab_starting_requests_.erase(it); |
| 119 return save_package; | 119 return save_package; |
| 120 } | 120 } |
| 121 | 121 |
| 122 return NULL; | 122 return NULL; |
| 123 } | 123 } |
| 124 | 124 |
| 125 void SaveFileManager::RequireSaveJobFromOtherSource(SaveFileCreateInfo* info) { | 125 void SaveFileManager::RequireSaveJobFromOtherSource(SaveFileCreateInfo* info) { |
| 126 // This function must be called on the UI thread, because the io_loop_ | 126 // This function must be called on the UI thread, because the io_loop_ |
| 127 // pointer may be junk when we use it on file thread. We can only rely on the | 127 // pointer may be junk when we use it on file thread. We can only rely on the |
| 128 // io_loop_ pointer being valid when we run code on the UI thread (or on | 128 // io_loop_ pointer being valid when we run code on the UI thread (or on |
| 129 // the IO thread. | 129 // the IO thread. |
| 130 DCHECK(MessageLoop::current() == ui_loop_); | 130 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 131 DCHECK(info->save_id == -1); | 131 DCHECK_EQ(info->save_id, -1); |
| 132 // Since the data will come from render process, so we need to start | 132 // Since the data will come from render process, so we need to start |
| 133 // this kind of save job by ourself. | 133 // this kind of save job by ourself. |
| 134 io_loop_->PostTask(FROM_HERE, | 134 io_loop_->PostTask(FROM_HERE, |
| 135 NewRunnableMethod(this, | 135 NewRunnableMethod(this, |
| 136 &SaveFileManager::OnRequireSaveJobFromOtherSource, | 136 &SaveFileManager::OnRequireSaveJobFromOtherSource, |
| 137 info)); | 137 info)); |
| 138 } | 138 } |
| 139 | 139 |
| 140 // Look up a SavePackage according to a save id. | 140 // Look up a SavePackage according to a save id. |
| 141 SavePackage* SaveFileManager::LookupPackage(int save_id) { | 141 SavePackage* SaveFileManager::LookupPackage(int save_id) { |
| 142 DCHECK(MessageLoop::current() == ui_loop_); | 142 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 143 SavePackageMap::iterator it = packages_.find(save_id); | 143 SavePackageMap::iterator it = packages_.find(save_id); |
| 144 if (it != packages_.end()) | 144 if (it != packages_.end()) |
| 145 return it->second; | 145 return it->second; |
| 146 return NULL; | 146 return NULL; |
| 147 } | 147 } |
| 148 | 148 |
| 149 // Call from SavePackage for starting a saving job | 149 // Call from SavePackage for starting a saving job |
| 150 void SaveFileManager::SaveURL(const GURL& url, | 150 void SaveFileManager::SaveURL(const GURL& url, |
| 151 const GURL& referrer, | 151 const GURL& referrer, |
| 152 int render_process_host_id, | 152 int render_process_host_id, |
| 153 int render_view_id, | 153 int render_view_id, |
| 154 SaveFileCreateInfo::SaveFileSource save_source, | 154 SaveFileCreateInfo::SaveFileSource save_source, |
| 155 const FilePath& file_full_path, | 155 const FilePath& file_full_path, |
| 156 URLRequestContext* request_context, | 156 URLRequestContext* request_context, |
| 157 SavePackage* save_package) { | 157 SavePackage* save_package) { |
| 158 DCHECK(MessageLoop::current() == ui_loop_); | 158 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 159 if (!io_loop_) { | 159 if (!io_loop_) { |
| 160 NOTREACHED(); // Net IO thread must exist. | 160 NOTREACHED(); // Net IO thread must exist. |
| 161 return; | 161 return; |
| 162 } | 162 } |
| 163 | 163 |
| 164 // Register a saving job. | 164 // Register a saving job. |
| 165 RegisterStartingRequest(url, save_package); | 165 RegisterStartingRequest(url, save_package); |
| 166 if (save_source == SaveFileCreateInfo::SAVE_FILE_FROM_NET) { | 166 if (save_source == SaveFileCreateInfo::SAVE_FILE_FROM_NET) { |
| 167 DCHECK(url.is_valid()); | 167 DCHECK(url.is_valid()); |
| 168 | 168 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 187 } | 187 } |
| 188 | 188 |
| 189 // Utility function for look up table maintenance, called on the UI thread. | 189 // Utility function for look up table maintenance, called on the UI thread. |
| 190 // A manager may have multiple save page job (SavePackage) in progress, | 190 // A manager may have multiple save page job (SavePackage) in progress, |
| 191 // so we just look up the save id and remove it from the tracking table. | 191 // so we just look up the save id and remove it from the tracking table. |
| 192 // If the save id is -1, it means we just send a request to save, but the | 192 // If the save id is -1, it means we just send a request to save, but the |
| 193 // saving action has still not happened, need to call UnregisterStartingRequest | 193 // saving action has still not happened, need to call UnregisterStartingRequest |
| 194 // to remove it from the tracking map. | 194 // to remove it from the tracking map. |
| 195 void SaveFileManager::RemoveSaveFile(int save_id, const GURL& save_url, | 195 void SaveFileManager::RemoveSaveFile(int save_id, const GURL& save_url, |
| 196 SavePackage* package) { | 196 SavePackage* package) { |
| 197 DCHECK(MessageLoop::current() == ui_loop_ && package); | 197 DCHECK(package); |
| 198 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 198 // A save page job(SavePackage) can only have one manager, | 199 // A save page job(SavePackage) can only have one manager, |
| 199 // so remove it if it exists. | 200 // so remove it if it exists. |
| 200 if (save_id == -1) { | 201 if (save_id == -1) { |
| 201 SavePackage* old_package = UnregisterStartingRequest(save_url, | 202 SavePackage* old_package = UnregisterStartingRequest(save_url, |
| 202 package->tab_id()); | 203 package->tab_id()); |
| 203 DCHECK(old_package == package); | 204 DCHECK_EQ(old_package, package); |
| 204 } else { | 205 } else { |
| 205 SavePackageMap::iterator it = packages_.find(save_id); | 206 SavePackageMap::iterator it = packages_.find(save_id); |
| 206 if (it != packages_.end()) | 207 if (it != packages_.end()) |
| 207 packages_.erase(it); | 208 packages_.erase(it); |
| 208 } | 209 } |
| 209 } | 210 } |
| 210 | 211 |
| 211 // Static | 212 // Static |
| 212 // Utility function for converting request IDs to a TabContents. Must be called | 213 // Utility function for converting request IDs to a TabContents. Must be called |
| 213 // only on the UI thread. | 214 // only on the UI thread. |
| 214 SavePackage* SaveFileManager::GetSavePackageFromRenderIds( | 215 SavePackage* SaveFileManager::GetSavePackageFromRenderIds( |
| 215 int render_process_id, int render_view_id) { | 216 int render_process_id, int render_view_id) { |
| 216 TabContents* contents = tab_util::GetTabContentsByID(render_process_id, | 217 TabContents* contents = tab_util::GetTabContentsByID(render_process_id, |
| 217 render_view_id); | 218 render_view_id); |
| 218 if (contents) | 219 if (contents) |
| 219 return contents->save_package(); | 220 return contents->save_package(); |
| 220 | 221 |
| 221 return NULL; | 222 return NULL; |
| 222 } | 223 } |
| 223 | 224 |
| 224 // Utility function for deleting specified file. | 225 // Utility function for deleting specified file. |
| 225 void SaveFileManager::DeleteDirectoryOrFile(const FilePath& full_path, | 226 void SaveFileManager::DeleteDirectoryOrFile(const FilePath& full_path, |
| 226 bool is_dir) { | 227 bool is_dir) { |
| 227 DCHECK(MessageLoop::current() == ui_loop_); | 228 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 228 MessageLoop* loop = file_loop(); | 229 MessageLoop* loop = file_loop(); |
| 229 DCHECK(loop); | 230 DCHECK(loop); |
| 230 loop->PostTask(FROM_HERE, | 231 loop->PostTask(FROM_HERE, |
| 231 NewRunnableMethod(this, | 232 NewRunnableMethod(this, |
| 232 &SaveFileManager::OnDeleteDirectoryOrFile, | 233 &SaveFileManager::OnDeleteDirectoryOrFile, |
| 233 full_path, | 234 full_path, |
| 234 is_dir)); | 235 is_dir)); |
| 235 } | 236 } |
| 236 | 237 |
| 237 void SaveFileManager::SendCancelRequest(int save_id) { | 238 void SaveFileManager::SendCancelRequest(int save_id) { |
| 238 // Cancel the request which has specific save id. | 239 // Cancel the request which has specific save id. |
| 239 DCHECK(save_id > -1); | 240 DCHECK_GT(save_id, -1); |
| 240 MessageLoop* loop = file_loop(); | 241 MessageLoop* loop = file_loop(); |
| 241 DCHECK(loop); | 242 DCHECK(loop); |
| 242 loop->PostTask(FROM_HERE, | 243 loop->PostTask(FROM_HERE, |
| 243 NewRunnableMethod(this, | 244 NewRunnableMethod(this, |
| 244 &SaveFileManager::CancelSave, | 245 &SaveFileManager::CancelSave, |
| 245 save_id)); | 246 save_id)); |
| 246 } | 247 } |
| 247 | 248 |
| 248 // Notifications sent from the IO thread and run on the file thread: | 249 // Notifications sent from the IO thread and run on the file thread: |
| 249 | 250 |
| 250 // The IO thread created |info|, but the file thread (this method) uses it | 251 // The IO thread created |info|, but the file thread (this method) uses it |
| 251 // to create a SaveFile which will hold and finally destroy |info|. It will | 252 // to create a SaveFile which will hold and finally destroy |info|. It will |
| 252 // then passes |info| to the UI thread for reporting saving status. | 253 // then passes |info| to the UI thread for reporting saving status. |
| 253 void SaveFileManager::StartSave(SaveFileCreateInfo* info) { | 254 void SaveFileManager::StartSave(SaveFileCreateInfo* info) { |
| 254 DCHECK(MessageLoop::current() == file_loop()); | 255 DCHECK_EQ(MessageLoop::current(), file_loop()); |
| 255 DCHECK(info); | 256 DCHECK(info); |
| 256 SaveFile* save_file = new SaveFile(info); | 257 SaveFile* save_file = new SaveFile(info); |
| 257 DCHECK(LookupSaveFile(info->save_id) == NULL); | 258 DCHECK(!LookupSaveFile(info->save_id)); |
| 258 save_file_map_[info->save_id] = save_file; | 259 save_file_map_[info->save_id] = save_file; |
| 259 info->path = save_file->full_path(); | 260 info->path = save_file->full_path(); |
| 260 | 261 |
| 261 ui_loop_->PostTask(FROM_HERE, | 262 ui_loop_->PostTask(FROM_HERE, |
| 262 NewRunnableMethod(this, | 263 NewRunnableMethod(this, |
| 263 &SaveFileManager::OnStartSave, | 264 &SaveFileManager::OnStartSave, |
| 264 info)); | 265 info)); |
| 265 } | 266 } |
| 266 | 267 |
| 267 // We do forward an update to the UI thread here, since we do not use timer to | 268 // We do forward an update to the UI thread here, since we do not use timer to |
| 268 // update the UI. If the user has canceled the saving action (in the UI | 269 // update the UI. If the user has canceled the saving action (in the UI |
| 269 // thread). We may receive a few more updates before the IO thread gets the | 270 // thread). We may receive a few more updates before the IO thread gets the |
| 270 // cancel message. We just delete the data since the SaveFile has been deleted. | 271 // cancel message. We just delete the data since the SaveFile has been deleted. |
| 271 void SaveFileManager::UpdateSaveProgress(int save_id, | 272 void SaveFileManager::UpdateSaveProgress(int save_id, |
| 272 net::IOBuffer* data, | 273 net::IOBuffer* data, |
| 273 int data_len) { | 274 int data_len) { |
| 274 DCHECK(MessageLoop::current() == file_loop()); | 275 DCHECK_EQ(MessageLoop::current(), file_loop()); |
| 275 SaveFile* save_file = LookupSaveFile(save_id); | 276 SaveFile* save_file = LookupSaveFile(save_id); |
| 276 if (save_file) { | 277 if (save_file) { |
| 277 bool write_success = save_file->AppendDataToFile(data->data(), data_len); | 278 bool write_success = save_file->AppendDataToFile(data->data(), data_len); |
| 278 ui_loop_->PostTask(FROM_HERE, | 279 ui_loop_->PostTask(FROM_HERE, |
| 279 NewRunnableMethod(this, | 280 NewRunnableMethod(this, |
| 280 &SaveFileManager::OnUpdateSaveProgress, | 281 &SaveFileManager::OnUpdateSaveProgress, |
| 281 save_file->save_id(), | 282 save_file->save_id(), |
| 282 save_file->bytes_so_far(), | 283 save_file->bytes_so_far(), |
| 283 write_success)); | 284 write_success)); |
| 284 } | 285 } |
| 285 data->Release(); | 286 data->Release(); |
| 286 } | 287 } |
| 287 | 288 |
| 288 // The IO thread will call this when saving is completed or it got error when | 289 // The IO thread will call this when saving is completed or it got error when |
| 289 // fetching data. In the former case, we forward the message to OnSaveFinished | 290 // fetching data. In the former case, we forward the message to OnSaveFinished |
| 290 // in UI thread. In the latter case, the save ID will be -1, which means the | 291 // in UI thread. In the latter case, the save ID will be -1, which means the |
| 291 // saving action did not even start, so we need to call OnErrorFinished in UI | 292 // saving action did not even start, so we need to call OnErrorFinished in UI |
| 292 // thread, which will use the save URL to find corresponding request record and | 293 // thread, which will use the save URL to find corresponding request record and |
| 293 // delete it. | 294 // delete it. |
| 294 void SaveFileManager::SaveFinished(int save_id, | 295 void SaveFileManager::SaveFinished(int save_id, |
| 295 GURL save_url, | 296 GURL save_url, |
| 296 int render_process_id, | 297 int render_process_id, |
| 297 bool is_success) { | 298 bool is_success) { |
| 298 DCHECK(MessageLoop::current() == file_loop()); | 299 DCHECK_EQ(MessageLoop::current(), file_loop()); |
| 299 SaveFileMap::iterator it = save_file_map_.find(save_id); | 300 SaveFileMap::iterator it = save_file_map_.find(save_id); |
| 300 if (it != save_file_map_.end()) { | 301 if (it != save_file_map_.end()) { |
| 301 SaveFile* save_file = it->second; | 302 SaveFile* save_file = it->second; |
| 302 ui_loop_->PostTask(FROM_HERE, | 303 ui_loop_->PostTask(FROM_HERE, |
| 303 NewRunnableMethod(this, | 304 NewRunnableMethod(this, |
| 304 &SaveFileManager::OnSaveFinished, | 305 &SaveFileManager::OnSaveFinished, |
| 305 save_id, | 306 save_id, |
| 306 save_file->bytes_so_far(), | 307 save_file->bytes_so_far(), |
| 307 is_success)); | 308 is_success)); |
| 308 | 309 |
| 309 save_file->Finish(); | 310 save_file->Finish(); |
| 310 } else if (save_id == -1) { | 311 } else if (save_id == -1) { |
| 311 // Before saving started, we got error. We still call finish process. | 312 // Before saving started, we got error. We still call finish process. |
| 312 DCHECK(!save_url.is_empty()); | 313 DCHECK(!save_url.is_empty()); |
| 313 ui_loop_->PostTask(FROM_HERE, | 314 ui_loop_->PostTask(FROM_HERE, |
| 314 NewRunnableMethod(this, | 315 NewRunnableMethod(this, |
| 315 &SaveFileManager::OnErrorFinished, | 316 &SaveFileManager::OnErrorFinished, |
| 316 save_url, | 317 save_url, |
| 317 render_process_id)); | 318 render_process_id)); |
| 318 } | 319 } |
| 319 } | 320 } |
| 320 | 321 |
| 321 // Notifications sent from the file thread and run on the UI thread. | 322 // Notifications sent from the file thread and run on the UI thread. |
| 322 | 323 |
| 323 void SaveFileManager::OnStartSave(const SaveFileCreateInfo* info) { | 324 void SaveFileManager::OnStartSave(const SaveFileCreateInfo* info) { |
| 324 DCHECK(MessageLoop::current() == ui_loop_); | 325 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 325 SavePackage* save_package = | 326 SavePackage* save_package = |
| 326 GetSavePackageFromRenderIds(info->render_process_id, | 327 GetSavePackageFromRenderIds(info->render_process_id, |
| 327 info->render_view_id); | 328 info->render_view_id); |
| 328 if (!save_package) { | 329 if (!save_package) { |
| 329 // Cancel this request. | 330 // Cancel this request. |
| 330 SendCancelRequest(info->save_id); | 331 SendCancelRequest(info->save_id); |
| 331 return; | 332 return; |
| 332 } | 333 } |
| 333 | 334 |
| 334 // Insert started saving job to tracking list. | 335 // Insert started saving job to tracking list. |
| 335 SavePackageMap::iterator sit = packages_.find(info->save_id); | 336 SavePackageMap::iterator sit = packages_.find(info->save_id); |
| 336 if (sit == packages_.end()) { | 337 if (sit == packages_.end()) { |
| 337 // Find the registered request. If we can not find, it means we have | 338 // Find the registered request. If we can not find, it means we have |
| 338 // canceled the job before. | 339 // canceled the job before. |
| 339 SavePackage* old_save_package = UnregisterStartingRequest(info->url, | 340 SavePackage* old_save_package = UnregisterStartingRequest(info->url, |
| 340 info->render_process_id); | 341 info->render_process_id); |
| 341 if (!old_save_package) { | 342 if (!old_save_package) { |
| 342 // Cancel this request. | 343 // Cancel this request. |
| 343 SendCancelRequest(info->save_id); | 344 SendCancelRequest(info->save_id); |
| 344 return; | 345 return; |
| 345 } | 346 } |
| 346 DCHECK(old_save_package == save_package); | 347 DCHECK_EQ(old_save_package, save_package); |
| 347 packages_[info->save_id] = save_package; | 348 packages_[info->save_id] = save_package; |
| 348 } else { | 349 } else { |
| 349 NOTREACHED(); | 350 NOTREACHED(); |
| 350 } | 351 } |
| 351 | 352 |
| 352 // Forward this message to SavePackage. | 353 // Forward this message to SavePackage. |
| 353 save_package->StartSave(info); | 354 save_package->StartSave(info); |
| 354 } | 355 } |
| 355 | 356 |
| 356 void SaveFileManager::OnUpdateSaveProgress(int save_id, int64 bytes_so_far, | 357 void SaveFileManager::OnUpdateSaveProgress(int save_id, int64 bytes_so_far, |
| 357 bool write_success) { | 358 bool write_success) { |
| 358 DCHECK(MessageLoop::current() == ui_loop_); | 359 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 359 SavePackage* package = LookupPackage(save_id); | 360 SavePackage* package = LookupPackage(save_id); |
| 360 if (package) | 361 if (package) |
| 361 package->UpdateSaveProgress(save_id, bytes_so_far, write_success); | 362 package->UpdateSaveProgress(save_id, bytes_so_far, write_success); |
| 362 else | 363 else |
| 363 SendCancelRequest(save_id); | 364 SendCancelRequest(save_id); |
| 364 } | 365 } |
| 365 | 366 |
| 366 void SaveFileManager::OnSaveFinished(int save_id, | 367 void SaveFileManager::OnSaveFinished(int save_id, |
| 367 int64 bytes_so_far, | 368 int64 bytes_so_far, |
| 368 bool is_success) { | 369 bool is_success) { |
| 369 DCHECK(MessageLoop::current() == ui_loop_); | 370 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 370 SavePackage* package = LookupPackage(save_id); | 371 SavePackage* package = LookupPackage(save_id); |
| 371 if (package) | 372 if (package) |
| 372 package->SaveFinished(save_id, bytes_so_far, is_success); | 373 package->SaveFinished(save_id, bytes_so_far, is_success); |
| 373 } | 374 } |
| 374 | 375 |
| 375 void SaveFileManager::OnErrorFinished(GURL save_url, int tab_id) { | 376 void SaveFileManager::OnErrorFinished(GURL save_url, int tab_id) { |
| 376 DCHECK(MessageLoop::current() == ui_loop_); | 377 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 377 SavePackage* save_package = UnregisterStartingRequest(save_url, tab_id); | 378 SavePackage* save_package = UnregisterStartingRequest(save_url, tab_id); |
| 378 if (save_package) | 379 if (save_package) |
| 379 save_package->SaveFailed(save_url); | 380 save_package->SaveFailed(save_url); |
| 380 } | 381 } |
| 381 | 382 |
| 382 void SaveFileManager::OnCancelSaveRequest(int render_process_id, | 383 void SaveFileManager::OnCancelSaveRequest(int render_process_id, |
| 383 int request_id) { | 384 int request_id) { |
| 384 DCHECK(MessageLoop::current() == ui_loop_); | 385 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 385 DCHECK(io_loop_); | 386 DCHECK(io_loop_); |
| 386 io_loop_->PostTask(FROM_HERE, | 387 io_loop_->PostTask(FROM_HERE, |
| 387 NewRunnableMethod(this, | 388 NewRunnableMethod(this, |
| 388 &SaveFileManager::ExecuteCancelSaveRequest, | 389 &SaveFileManager::ExecuteCancelSaveRequest, |
| 389 render_process_id, | 390 render_process_id, |
| 390 request_id)); | 391 request_id)); |
| 391 } | 392 } |
| 392 | 393 |
| 393 // Notifications sent from the UI thread and run on the IO thread. | 394 // Notifications sent from the UI thread and run on the IO thread. |
| 394 | 395 |
| 395 void SaveFileManager::OnSaveURL(const GURL& url, | 396 void SaveFileManager::OnSaveURL(const GURL& url, |
| 396 const GURL& referrer, | 397 const GURL& referrer, |
| 397 int render_process_host_id, | 398 int render_process_host_id, |
| 398 int render_view_id, | 399 int render_view_id, |
| 399 URLRequestContext* request_context) { | 400 URLRequestContext* request_context) { |
| 400 DCHECK(MessageLoop::current() == io_loop_); | 401 DCHECK_EQ(MessageLoop::current(), io_loop_); |
| 401 resource_dispatcher_host_->BeginSaveFile(url, | 402 resource_dispatcher_host_->BeginSaveFile(url, |
| 402 referrer, | 403 referrer, |
| 403 render_process_host_id, | 404 render_process_host_id, |
| 404 render_view_id, | 405 render_view_id, |
| 405 request_context); | 406 request_context); |
| 406 } | 407 } |
| 407 | 408 |
| 408 void SaveFileManager::OnRequireSaveJobFromOtherSource( | 409 void SaveFileManager::OnRequireSaveJobFromOtherSource( |
| 409 SaveFileCreateInfo* info) { | 410 SaveFileCreateInfo* info) { |
| 410 DCHECK(MessageLoop::current() == io_loop_); | 411 DCHECK_EQ(MessageLoop::current(), io_loop_); |
| 411 DCHECK(info->save_id == -1); | 412 DCHECK_EQ(info->save_id, -1); |
| 412 // Generate a unique save id. | 413 // Generate a unique save id. |
| 413 info->save_id = GetNextId(); | 414 info->save_id = GetNextId(); |
| 414 // Start real saving action. | 415 // Start real saving action. |
| 415 MessageLoop* loop = file_loop(); | 416 MessageLoop* loop = file_loop(); |
| 416 DCHECK(loop); | 417 DCHECK(loop); |
| 417 loop->PostTask(FROM_HERE, | 418 loop->PostTask(FROM_HERE, |
| 418 NewRunnableMethod(this, | 419 NewRunnableMethod(this, |
| 419 &SaveFileManager::StartSave, | 420 &SaveFileManager::StartSave, |
| 420 info)); | 421 info)); |
| 421 } | 422 } |
| 422 | 423 |
| 423 void SaveFileManager::ExecuteCancelSaveRequest(int render_process_id, | 424 void SaveFileManager::ExecuteCancelSaveRequest(int render_process_id, |
| 424 int request_id) { | 425 int request_id) { |
| 425 DCHECK(MessageLoop::current() == io_loop_); | 426 DCHECK_EQ(MessageLoop::current(), io_loop_); |
| 426 resource_dispatcher_host_->CancelRequest(render_process_id, | 427 resource_dispatcher_host_->CancelRequest(render_process_id, |
| 427 request_id, | 428 request_id, |
| 428 false); | 429 false); |
| 429 } | 430 } |
| 430 | 431 |
| 431 // Notifications sent from the UI thread and run on the file thread. | 432 // Notifications sent from the UI thread and run on the file thread. |
| 432 | 433 |
| 433 // This method will be sent via a user action, or shutdown on the UI thread, | 434 // This method will be sent via a user action, or shutdown on the UI thread, |
| 434 // and run on the file thread. We don't post a message back for cancels, | 435 // and run on the file thread. We don't post a message back for cancels, |
| 435 // but we do forward the cancel to the IO thread. Since this message has been | 436 // but we do forward the cancel to the IO thread. Since this message has been |
| 436 // sent from the UI thread, the saving job may have already completed and | 437 // sent from the UI thread, the saving job may have already completed and |
| 437 // won't exist in our map. | 438 // won't exist in our map. |
| 438 void SaveFileManager::CancelSave(int save_id) { | 439 void SaveFileManager::CancelSave(int save_id) { |
| 439 DCHECK(MessageLoop::current() == file_loop()); | 440 DCHECK_EQ(MessageLoop::current(), file_loop()); |
| 440 SaveFileMap::iterator it = save_file_map_.find(save_id); | 441 SaveFileMap::iterator it = save_file_map_.find(save_id); |
| 441 if (it != save_file_map_.end()) { | 442 if (it != save_file_map_.end()) { |
| 442 SaveFile* save_file = it->second; | 443 SaveFile* save_file = it->second; |
| 443 | 444 |
| 444 // If the data comes from the net IO thread, then forward the cancel | 445 // If the data comes from the net IO thread, then forward the cancel |
| 445 // message to IO thread. If the data comes from other sources, just | 446 // message to IO thread. If the data comes from other sources, just |
| 446 // ignore the cancel message. | 447 // ignore the cancel message. |
| 447 if (save_file->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_NET) { | 448 if (save_file->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_NET) { |
| 448 ui_loop_->PostTask(FROM_HERE, | 449 ui_loop_->PostTask(FROM_HERE, |
| 449 NewRunnableMethod(this, | 450 NewRunnableMethod(this, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 466 delete save_file; | 467 delete save_file; |
| 467 } | 468 } |
| 468 } | 469 } |
| 469 | 470 |
| 470 // It is possible that SaveItem which has specified save_id has been canceled | 471 // It is possible that SaveItem which has specified save_id has been canceled |
| 471 // before this function runs. So if we can not find corresponding SaveFile by | 472 // before this function runs. So if we can not find corresponding SaveFile by |
| 472 // using specified save_id, just return. | 473 // using specified save_id, just return. |
| 473 void SaveFileManager::SaveLocalFile(const GURL& original_file_url, | 474 void SaveFileManager::SaveLocalFile(const GURL& original_file_url, |
| 474 int save_id, | 475 int save_id, |
| 475 int render_process_id) { | 476 int render_process_id) { |
| 476 DCHECK(MessageLoop::current() == file_loop()); | 477 DCHECK_EQ(MessageLoop::current(), file_loop()); |
| 477 SaveFile* save_file = LookupSaveFile(save_id); | 478 SaveFile* save_file = LookupSaveFile(save_id); |
| 478 if (!save_file) | 479 if (!save_file) |
| 479 return; | 480 return; |
| 480 DCHECK(!save_file->path_renamed()); | 481 DCHECK(!save_file->path_renamed()); |
| 481 // If it has finished, just return. | 482 // If it has finished, just return. |
| 482 if (!save_file->in_progress()) | 483 if (!save_file->in_progress()) |
| 483 return; | 484 return; |
| 484 | 485 |
| 485 // Close the save file before the copy operation. | 486 // Close the save file before the copy operation. |
| 486 save_file->Finish(); | 487 save_file->Finish(); |
| 487 | 488 |
| 488 DCHECK(original_file_url.SchemeIsFile()); | 489 DCHECK(original_file_url.SchemeIsFile()); |
| 489 FilePath file_path; | 490 FilePath file_path; |
| 490 net::FileURLToFilePath(original_file_url, &file_path); | 491 net::FileURLToFilePath(original_file_url, &file_path); |
| 491 // If we can not get valid file path from original URL, treat it as | 492 // If we can not get valid file path from original URL, treat it as |
| 492 // disk error. | 493 // disk error. |
| 493 if (file_path.empty()) | 494 if (file_path.empty()) |
| 494 SaveFinished(save_id, original_file_url, render_process_id, false); | 495 SaveFinished(save_id, original_file_url, render_process_id, false); |
| 495 | 496 |
| 496 // Copy the local file to the temporary file. It will be renamed to its | 497 // Copy the local file to the temporary file. It will be renamed to its |
| 497 // final name later. | 498 // final name later. |
| 498 bool success = file_util::CopyFile(file_path, save_file->full_path()); | 499 bool success = file_util::CopyFile(file_path, save_file->full_path()); |
| 499 if (!success) | 500 if (!success) |
| 500 file_util::Delete(save_file->full_path(), false); | 501 file_util::Delete(save_file->full_path(), false); |
| 501 SaveFinished(save_id, original_file_url, render_process_id, success); | 502 SaveFinished(save_id, original_file_url, render_process_id, success); |
| 502 } | 503 } |
| 503 | 504 |
| 504 void SaveFileManager::OnDeleteDirectoryOrFile(const FilePath& full_path, | 505 void SaveFileManager::OnDeleteDirectoryOrFile(const FilePath& full_path, |
| 505 bool is_dir) { | 506 bool is_dir) { |
| 506 DCHECK(MessageLoop::current() == file_loop()); | 507 DCHECK_EQ(MessageLoop::current(), file_loop()); |
| 507 DCHECK(!full_path.empty()); | 508 DCHECK(!full_path.empty()); |
| 508 | 509 |
| 509 file_util::Delete(full_path, is_dir); | 510 file_util::Delete(full_path, is_dir); |
| 510 } | 511 } |
| 511 | 512 |
| 512 // Open a saved page package, show it in a Windows Explorer window. | 513 // Open a saved page package, show it in a Windows Explorer window. |
| 513 // We run on this thread to avoid blocking the UI with slow Shell operations. | 514 // We run on this thread to avoid blocking the UI with slow Shell operations. |
| 514 #if !defined(OS_MACOSX) | 515 #if !defined(OS_MACOSX) |
| 515 void SaveFileManager::OnShowSavedFileInShell(const FilePath full_path) { | 516 void SaveFileManager::OnShowSavedFileInShell(const FilePath full_path) { |
| 516 DCHECK(MessageLoop::current() == file_loop()); | 517 DCHECK_EQ(MessageLoop::current(), file_loop()); |
| 517 platform_util::ShowItemInFolder(full_path); | 518 platform_util::ShowItemInFolder(full_path); |
| 518 } | 519 } |
| 519 #endif | 520 #endif |
| 520 | 521 |
| 521 void SaveFileManager::RenameAllFiles( | 522 void SaveFileManager::RenameAllFiles( |
| 522 const FinalNameList& final_names, | 523 const FinalNameList& final_names, |
| 523 const FilePath& resource_dir, | 524 const FilePath& resource_dir, |
| 524 int render_process_id, | 525 int render_process_id, |
| 525 int render_view_id) { | 526 int render_view_id) { |
| 526 DCHECK(MessageLoop::current() == file_loop()); | 527 DCHECK_EQ(MessageLoop::current(), file_loop()); |
| 527 | 528 |
| 528 if (!resource_dir.empty() && !file_util::PathExists(resource_dir)) | 529 if (!resource_dir.empty() && !file_util::PathExists(resource_dir)) |
| 529 file_util::CreateDirectory(resource_dir); | 530 file_util::CreateDirectory(resource_dir); |
| 530 | 531 |
| 531 for (FinalNameList::const_iterator i = final_names.begin(); | 532 for (FinalNameList::const_iterator i = final_names.begin(); |
| 532 i != final_names.end(); ++i) { | 533 i != final_names.end(); ++i) { |
| 533 SaveFileMap::iterator it = save_file_map_.find(i->first); | 534 SaveFileMap::iterator it = save_file_map_.find(i->first); |
| 534 if (it != save_file_map_.end()) { | 535 if (it != save_file_map_.end()) { |
| 535 SaveFile* save_file = it->second; | 536 SaveFile* save_file = it->second; |
| 536 DCHECK(!save_file->in_progress()); | 537 DCHECK(!save_file->in_progress()); |
| 537 save_file->Rename(i->second); | 538 save_file->Rename(i->second); |
| 538 delete save_file; | 539 delete save_file; |
| 539 save_file_map_.erase(it); | 540 save_file_map_.erase(it); |
| 540 } | 541 } |
| 541 } | 542 } |
| 542 | 543 |
| 543 ui_loop_->PostTask(FROM_HERE, | 544 ui_loop_->PostTask(FROM_HERE, |
| 544 NewRunnableMethod(this, | 545 NewRunnableMethod(this, |
| 545 &SaveFileManager::OnFinishSavePageJob, | 546 &SaveFileManager::OnFinishSavePageJob, |
| 546 render_process_id, | 547 render_process_id, |
| 547 render_view_id)); | 548 render_view_id)); |
| 548 } | 549 } |
| 549 | 550 |
| 550 void SaveFileManager::OnFinishSavePageJob(int render_process_id, | 551 void SaveFileManager::OnFinishSavePageJob(int render_process_id, |
| 551 int render_view_id) { | 552 int render_view_id) { |
| 552 DCHECK(MessageLoop::current() == ui_loop_); | 553 DCHECK_EQ(MessageLoop::current(), ui_loop_); |
| 553 | 554 |
| 554 SavePackage* save_package = | 555 SavePackage* save_package = |
| 555 GetSavePackageFromRenderIds(render_process_id, render_view_id); | 556 GetSavePackageFromRenderIds(render_process_id, render_view_id); |
| 556 | 557 |
| 557 if (save_package) { | 558 if (save_package) { |
| 558 // save_package is null if save was canceled. | 559 // save_package is null if save was canceled. |
| 559 save_package->Finish(); | 560 save_package->Finish(); |
| 560 } | 561 } |
| 561 } | 562 } |
| 562 | 563 |
| 563 void SaveFileManager::RemoveSavedFileFromFileMap( | 564 void SaveFileManager::RemoveSavedFileFromFileMap( |
| 564 const SaveIDList& save_ids) { | 565 const SaveIDList& save_ids) { |
| 565 DCHECK(MessageLoop::current() == file_loop()); | 566 DCHECK_EQ(MessageLoop::current(), file_loop()); |
| 566 | 567 |
| 567 for (SaveIDList::const_iterator i = save_ids.begin(); | 568 for (SaveIDList::const_iterator i = save_ids.begin(); |
| 568 i != save_ids.end(); ++i) { | 569 i != save_ids.end(); ++i) { |
| 569 SaveFileMap::iterator it = save_file_map_.find(*i); | 570 SaveFileMap::iterator it = save_file_map_.find(*i); |
| 570 if (it != save_file_map_.end()) { | 571 if (it != save_file_map_.end()) { |
| 571 SaveFile* save_file = it->second; | 572 SaveFile* save_file = it->second; |
| 572 DCHECK(!save_file->in_progress()); | 573 DCHECK(!save_file->in_progress()); |
| 573 file_util::Delete(save_file->full_path(), false); | 574 file_util::Delete(save_file->full_path(), false); |
| 574 delete save_file; | 575 delete save_file; |
| 575 save_file_map_.erase(it); | 576 save_file_map_.erase(it); |
| 576 } | 577 } |
| 577 } | 578 } |
| 578 } | 579 } |
| 580 |
| 581 void SaveFileManager::CreateDownloadDirectory(FilePath save_dir, |
| 582 SavePackage* save_package) { |
| 583 file_util::CreateDirectory(save_dir); |
| 584 ui_loop_->PostTask(FROM_HERE, |
| 585 NewRunnableMethod(save_package, |
| 586 &SavePackage::ContinueGetSaveInfo, |
| 587 save_dir)); |
| 588 } |
| OLD | NEW |