| 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 = GetSaveLoop(); | 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() == GetSaveLoop()); | 68 DCHECK(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. |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 if (contents) | 218 if (contents) |
| 219 return contents->save_package(); | 219 return contents->save_package(); |
| 220 | 220 |
| 221 return NULL; | 221 return NULL; |
| 222 } | 222 } |
| 223 | 223 |
| 224 // Utility function for deleting specified file. | 224 // Utility function for deleting specified file. |
| 225 void SaveFileManager::DeleteDirectoryOrFile(const FilePath& full_path, | 225 void SaveFileManager::DeleteDirectoryOrFile(const FilePath& full_path, |
| 226 bool is_dir) { | 226 bool is_dir) { |
| 227 DCHECK(MessageLoop::current() == ui_loop_); | 227 DCHECK(MessageLoop::current() == ui_loop_); |
| 228 MessageLoop* loop = GetSaveLoop(); | 228 MessageLoop* loop = file_loop(); |
| 229 DCHECK(loop); | 229 DCHECK(loop); |
| 230 loop->PostTask(FROM_HERE, | 230 loop->PostTask(FROM_HERE, |
| 231 NewRunnableMethod(this, | 231 NewRunnableMethod(this, |
| 232 &SaveFileManager::OnDeleteDirectoryOrFile, | 232 &SaveFileManager::OnDeleteDirectoryOrFile, |
| 233 full_path, | 233 full_path, |
| 234 is_dir)); | 234 is_dir)); |
| 235 } | 235 } |
| 236 | 236 |
| 237 void SaveFileManager::SendCancelRequest(int save_id) { | 237 void SaveFileManager::SendCancelRequest(int save_id) { |
| 238 // Cancel the request which has specific save id. | 238 // Cancel the request which has specific save id. |
| 239 DCHECK(save_id > -1); | 239 DCHECK(save_id > -1); |
| 240 MessageLoop* loop = GetSaveLoop(); | 240 MessageLoop* loop = file_loop(); |
| 241 DCHECK(loop); | 241 DCHECK(loop); |
| 242 loop->PostTask(FROM_HERE, | 242 loop->PostTask(FROM_HERE, |
| 243 NewRunnableMethod(this, | 243 NewRunnableMethod(this, |
| 244 &SaveFileManager::CancelSave, | 244 &SaveFileManager::CancelSave, |
| 245 save_id)); | 245 save_id)); |
| 246 } | 246 } |
| 247 | 247 |
| 248 // Notifications sent from the IO thread and run on the file thread: | 248 // Notifications sent from the IO thread and run on the file thread: |
| 249 | 249 |
| 250 // The IO thread created |info|, but the file thread (this method) uses it | 250 // 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 | 251 // 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. | 252 // then passes |info| to the UI thread for reporting saving status. |
| 253 void SaveFileManager::StartSave(SaveFileCreateInfo* info) { | 253 void SaveFileManager::StartSave(SaveFileCreateInfo* info) { |
| 254 DCHECK(MessageLoop::current() == GetSaveLoop()); | 254 DCHECK(MessageLoop::current() == file_loop()); |
| 255 DCHECK(info); | 255 DCHECK(info); |
| 256 SaveFile* save_file = new SaveFile(info); | 256 SaveFile* save_file = new SaveFile(info); |
| 257 DCHECK(LookupSaveFile(info->save_id) == NULL); | 257 DCHECK(LookupSaveFile(info->save_id) == NULL); |
| 258 save_file_map_[info->save_id] = save_file; | 258 save_file_map_[info->save_id] = save_file; |
| 259 info->path = save_file->full_path(); | 259 info->path = save_file->full_path(); |
| 260 | 260 |
| 261 ui_loop_->PostTask(FROM_HERE, | 261 ui_loop_->PostTask(FROM_HERE, |
| 262 NewRunnableMethod(this, | 262 NewRunnableMethod(this, |
| 263 &SaveFileManager::OnStartSave, | 263 &SaveFileManager::OnStartSave, |
| 264 info)); | 264 info)); |
| 265 } | 265 } |
| 266 | 266 |
| 267 // We do forward an update to the UI thread here, since we do not use timer to | 267 // 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 | 268 // 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 | 269 // 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. | 270 // cancel message. We just delete the data since the SaveFile has been deleted. |
| 271 void SaveFileManager::UpdateSaveProgress(int save_id, | 271 void SaveFileManager::UpdateSaveProgress(int save_id, |
| 272 net::IOBuffer* data, | 272 net::IOBuffer* data, |
| 273 int data_len) { | 273 int data_len) { |
| 274 DCHECK(MessageLoop::current() == GetSaveLoop()); | 274 DCHECK(MessageLoop::current() == file_loop()); |
| 275 SaveFile* save_file = LookupSaveFile(save_id); | 275 SaveFile* save_file = LookupSaveFile(save_id); |
| 276 if (save_file) { | 276 if (save_file) { |
| 277 bool write_success = save_file->AppendDataToFile(data->data(), data_len); | 277 bool write_success = save_file->AppendDataToFile(data->data(), data_len); |
| 278 ui_loop_->PostTask(FROM_HERE, | 278 ui_loop_->PostTask(FROM_HERE, |
| 279 NewRunnableMethod(this, | 279 NewRunnableMethod(this, |
| 280 &SaveFileManager::OnUpdateSaveProgress, | 280 &SaveFileManager::OnUpdateSaveProgress, |
| 281 save_file->save_id(), | 281 save_file->save_id(), |
| 282 save_file->bytes_so_far(), | 282 save_file->bytes_so_far(), |
| 283 write_success)); | 283 write_success)); |
| 284 } | 284 } |
| 285 data->Release(); | 285 data->Release(); |
| 286 } | 286 } |
| 287 | 287 |
| 288 // The IO thread will call this when saving is completed or it got error when | 288 // 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 | 289 // 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 | 290 // 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 | 291 // 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 | 292 // thread, which will use the save URL to find corresponding request record and |
| 293 // delete it. | 293 // delete it. |
| 294 void SaveFileManager::SaveFinished(int save_id, | 294 void SaveFileManager::SaveFinished(int save_id, |
| 295 GURL save_url, | 295 GURL save_url, |
| 296 int render_process_id, | 296 int render_process_id, |
| 297 bool is_success) { | 297 bool is_success) { |
| 298 DCHECK(MessageLoop::current() == GetSaveLoop()); | 298 DCHECK(MessageLoop::current() == file_loop()); |
| 299 SaveFileMap::iterator it = save_file_map_.find(save_id); | 299 SaveFileMap::iterator it = save_file_map_.find(save_id); |
| 300 if (it != save_file_map_.end()) { | 300 if (it != save_file_map_.end()) { |
| 301 SaveFile* save_file = it->second; | 301 SaveFile* save_file = it->second; |
| 302 ui_loop_->PostTask(FROM_HERE, | 302 ui_loop_->PostTask(FROM_HERE, |
| 303 NewRunnableMethod(this, | 303 NewRunnableMethod(this, |
| 304 &SaveFileManager::OnSaveFinished, | 304 &SaveFileManager::OnSaveFinished, |
| 305 save_id, | 305 save_id, |
| 306 save_file->bytes_so_far(), | 306 save_file->bytes_so_far(), |
| 307 is_success)); | 307 is_success)); |
| 308 | 308 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 request_context); | 405 request_context); |
| 406 } | 406 } |
| 407 | 407 |
| 408 void SaveFileManager::OnRequireSaveJobFromOtherSource( | 408 void SaveFileManager::OnRequireSaveJobFromOtherSource( |
| 409 SaveFileCreateInfo* info) { | 409 SaveFileCreateInfo* info) { |
| 410 DCHECK(MessageLoop::current() == io_loop_); | 410 DCHECK(MessageLoop::current() == io_loop_); |
| 411 DCHECK(info->save_id == -1); | 411 DCHECK(info->save_id == -1); |
| 412 // Generate a unique save id. | 412 // Generate a unique save id. |
| 413 info->save_id = GetNextId(); | 413 info->save_id = GetNextId(); |
| 414 // Start real saving action. | 414 // Start real saving action. |
| 415 MessageLoop* loop = GetSaveLoop(); | 415 MessageLoop* loop = file_loop(); |
| 416 DCHECK(loop); | 416 DCHECK(loop); |
| 417 loop->PostTask(FROM_HERE, | 417 loop->PostTask(FROM_HERE, |
| 418 NewRunnableMethod(this, | 418 NewRunnableMethod(this, |
| 419 &SaveFileManager::StartSave, | 419 &SaveFileManager::StartSave, |
| 420 info)); | 420 info)); |
| 421 } | 421 } |
| 422 | 422 |
| 423 void SaveFileManager::ExecuteCancelSaveRequest(int render_process_id, | 423 void SaveFileManager::ExecuteCancelSaveRequest(int render_process_id, |
| 424 int request_id) { | 424 int request_id) { |
| 425 DCHECK(MessageLoop::current() == io_loop_); | 425 DCHECK(MessageLoop::current() == io_loop_); |
| 426 resource_dispatcher_host_->CancelRequest(render_process_id, | 426 resource_dispatcher_host_->CancelRequest(render_process_id, |
| 427 request_id, | 427 request_id, |
| 428 false); | 428 false); |
| 429 } | 429 } |
| 430 | 430 |
| 431 // Notifications sent from the UI thread and run on the file thread. | 431 // Notifications sent from the UI thread and run on the file thread. |
| 432 | 432 |
| 433 // This method will be sent via a user action, or shutdown on the UI thread, | 433 // 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, | 434 // 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 | 435 // 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 | 436 // sent from the UI thread, the saving job may have already completed and |
| 437 // won't exist in our map. | 437 // won't exist in our map. |
| 438 void SaveFileManager::CancelSave(int save_id) { | 438 void SaveFileManager::CancelSave(int save_id) { |
| 439 DCHECK(MessageLoop::current() == GetSaveLoop()); | 439 DCHECK(MessageLoop::current() == file_loop()); |
| 440 SaveFileMap::iterator it = save_file_map_.find(save_id); | 440 SaveFileMap::iterator it = save_file_map_.find(save_id); |
| 441 if (it != save_file_map_.end()) { | 441 if (it != save_file_map_.end()) { |
| 442 SaveFile* save_file = it->second; | 442 SaveFile* save_file = it->second; |
| 443 | 443 |
| 444 // If the data comes from the net IO thread, then forward the cancel | 444 // 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 | 445 // message to IO thread. If the data comes from other sources, just |
| 446 // ignore the cancel message. | 446 // ignore the cancel message. |
| 447 if (save_file->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_NET) { | 447 if (save_file->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_NET) { |
| 448 ui_loop_->PostTask(FROM_HERE, | 448 ui_loop_->PostTask(FROM_HERE, |
| 449 NewRunnableMethod(this, | 449 NewRunnableMethod(this, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 466 delete save_file; | 466 delete save_file; |
| 467 } | 467 } |
| 468 } | 468 } |
| 469 | 469 |
| 470 // It is possible that SaveItem which has specified save_id has been canceled | 470 // 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 | 471 // before this function runs. So if we can not find corresponding SaveFile by |
| 472 // using specified save_id, just return. | 472 // using specified save_id, just return. |
| 473 void SaveFileManager::SaveLocalFile(const GURL& original_file_url, | 473 void SaveFileManager::SaveLocalFile(const GURL& original_file_url, |
| 474 int save_id, | 474 int save_id, |
| 475 int render_process_id) { | 475 int render_process_id) { |
| 476 DCHECK(MessageLoop::current() == GetSaveLoop()); | 476 DCHECK(MessageLoop::current() == file_loop()); |
| 477 SaveFile* save_file = LookupSaveFile(save_id); | 477 SaveFile* save_file = LookupSaveFile(save_id); |
| 478 if (!save_file) | 478 if (!save_file) |
| 479 return; | 479 return; |
| 480 DCHECK(!save_file->path_renamed()); | 480 DCHECK(!save_file->path_renamed()); |
| 481 // If it has finished, just return. | 481 // If it has finished, just return. |
| 482 if (!save_file->in_progress()) | 482 if (!save_file->in_progress()) |
| 483 return; | 483 return; |
| 484 | 484 |
| 485 // Close the save file before the copy operation. | 485 // Close the save file before the copy operation. |
| 486 save_file->Finish(); | 486 save_file->Finish(); |
| 487 | 487 |
| 488 DCHECK(original_file_url.SchemeIsFile()); | 488 DCHECK(original_file_url.SchemeIsFile()); |
| 489 FilePath file_path; | 489 FilePath file_path; |
| 490 net::FileURLToFilePath(original_file_url, &file_path); | 490 net::FileURLToFilePath(original_file_url, &file_path); |
| 491 // If we can not get valid file path from original URL, treat it as | 491 // If we can not get valid file path from original URL, treat it as |
| 492 // disk error. | 492 // disk error. |
| 493 if (file_path.empty()) | 493 if (file_path.empty()) |
| 494 SaveFinished(save_id, original_file_url, render_process_id, false); | 494 SaveFinished(save_id, original_file_url, render_process_id, false); |
| 495 | 495 |
| 496 // Copy the local file to the temporary file. It will be renamed to its | 496 // Copy the local file to the temporary file. It will be renamed to its |
| 497 // final name later. | 497 // final name later. |
| 498 bool success = file_util::CopyFile(file_path, save_file->full_path()); | 498 bool success = file_util::CopyFile(file_path, save_file->full_path()); |
| 499 if (!success) | 499 if (!success) |
| 500 file_util::Delete(save_file->full_path(), false); | 500 file_util::Delete(save_file->full_path(), false); |
| 501 SaveFinished(save_id, original_file_url, render_process_id, success); | 501 SaveFinished(save_id, original_file_url, render_process_id, success); |
| 502 } | 502 } |
| 503 | 503 |
| 504 void SaveFileManager::OnDeleteDirectoryOrFile(const FilePath& full_path, | 504 void SaveFileManager::OnDeleteDirectoryOrFile(const FilePath& full_path, |
| 505 bool is_dir) { | 505 bool is_dir) { |
| 506 DCHECK(MessageLoop::current() == GetSaveLoop()); | 506 DCHECK(MessageLoop::current() == file_loop()); |
| 507 DCHECK(!full_path.empty()); | 507 DCHECK(!full_path.empty()); |
| 508 | 508 |
| 509 file_util::Delete(full_path, is_dir); | 509 file_util::Delete(full_path, is_dir); |
| 510 } | 510 } |
| 511 | 511 |
| 512 // Open a saved page package, show it in a Windows Explorer window. | 512 // 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. | 513 // We run on this thread to avoid blocking the UI with slow Shell operations. |
| 514 #if !defined(OS_MACOSX) |
| 514 void SaveFileManager::OnShowSavedFileInShell(const FilePath full_path) { | 515 void SaveFileManager::OnShowSavedFileInShell(const FilePath full_path) { |
| 515 DCHECK(MessageLoop::current() == GetSaveLoop()); | 516 DCHECK(MessageLoop::current() == file_loop()); |
| 516 platform_util::ShowItemInFolder(full_path); | 517 platform_util::ShowItemInFolder(full_path); |
| 517 } | 518 } |
| 519 #endif |
| 518 | 520 |
| 519 void SaveFileManager::RenameAllFiles( | 521 void SaveFileManager::RenameAllFiles( |
| 520 const FinalNameList& final_names, | 522 const FinalNameList& final_names, |
| 521 const FilePath& resource_dir, | 523 const FilePath& resource_dir, |
| 522 int render_process_id, | 524 int render_process_id, |
| 523 int render_view_id) { | 525 int render_view_id) { |
| 524 DCHECK(MessageLoop::current() == GetSaveLoop()); | 526 DCHECK(MessageLoop::current() == file_loop()); |
| 525 | 527 |
| 526 if (!resource_dir.empty() && !file_util::PathExists(resource_dir)) | 528 if (!resource_dir.empty() && !file_util::PathExists(resource_dir)) |
| 527 file_util::CreateDirectory(resource_dir); | 529 file_util::CreateDirectory(resource_dir); |
| 528 | 530 |
| 529 for (FinalNameList::const_iterator i = final_names.begin(); | 531 for (FinalNameList::const_iterator i = final_names.begin(); |
| 530 i != final_names.end(); ++i) { | 532 i != final_names.end(); ++i) { |
| 531 SaveFileMap::iterator it = save_file_map_.find(i->first); | 533 SaveFileMap::iterator it = save_file_map_.find(i->first); |
| 532 if (it != save_file_map_.end()) { | 534 if (it != save_file_map_.end()) { |
| 533 SaveFile* save_file = it->second; | 535 SaveFile* save_file = it->second; |
| 534 DCHECK(!save_file->in_progress()); | 536 DCHECK(!save_file->in_progress()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 553 GetSavePackageFromRenderIds(render_process_id, render_view_id); | 555 GetSavePackageFromRenderIds(render_process_id, render_view_id); |
| 554 | 556 |
| 555 if (save_package) { | 557 if (save_package) { |
| 556 // save_package is null if save was canceled. | 558 // save_package is null if save was canceled. |
| 557 save_package->Finish(); | 559 save_package->Finish(); |
| 558 } | 560 } |
| 559 } | 561 } |
| 560 | 562 |
| 561 void SaveFileManager::RemoveSavedFileFromFileMap( | 563 void SaveFileManager::RemoveSavedFileFromFileMap( |
| 562 const SaveIDList& save_ids) { | 564 const SaveIDList& save_ids) { |
| 563 DCHECK(MessageLoop::current() == GetSaveLoop()); | 565 DCHECK(MessageLoop::current() == file_loop()); |
| 564 | 566 |
| 565 for (SaveIDList::const_iterator i = save_ids.begin(); | 567 for (SaveIDList::const_iterator i = save_ids.begin(); |
| 566 i != save_ids.end(); ++i) { | 568 i != save_ids.end(); ++i) { |
| 567 SaveFileMap::iterator it = save_file_map_.find(*i); | 569 SaveFileMap::iterator it = save_file_map_.find(*i); |
| 568 if (it != save_file_map_.end()) { | 570 if (it != save_file_map_.end()) { |
| 569 SaveFile* save_file = it->second; | 571 SaveFile* save_file = it->second; |
| 570 DCHECK(!save_file->in_progress()); | 572 DCHECK(!save_file->in_progress()); |
| 571 file_util::Delete(save_file->full_path(), false); | 573 file_util::Delete(save_file->full_path(), false); |
| 572 delete save_file; | 574 delete save_file; |
| 573 save_file_map_.erase(it); | 575 save_file_map_.erase(it); |
| 574 } | 576 } |
| 575 } | 577 } |
| 576 } | 578 } |
| OLD | NEW |