OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/browser/download/download_manager.h" | 5 #include "chrome/browser/download/download_manager.h" |
6 | 6 |
7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
8 #include "app/resource_bundle.h" | 8 #include "app/resource_bundle.h" |
9 #include "base/callback.h" | 9 #include "base/callback.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 new OtherDownloadManagerObserver(this)); | 238 new OtherDownloadManagerObserver(this)); |
239 | 239 |
240 return true; | 240 return true; |
241 } | 241 } |
242 | 242 |
243 // We have received a message from DownloadFileManager about a new download. We | 243 // We have received a message from DownloadFileManager about a new download. We |
244 // create a download item and store it in our download map, and inform the | 244 // create a download item and store it in our download map, and inform the |
245 // history system of a new download. Since this method can be called while the | 245 // history system of a new download. Since this method can be called while the |
246 // history service thread is still reading the persistent state, we do not | 246 // history service thread is still reading the persistent state, we do not |
247 // insert the new DownloadItem into 'history_downloads_' or inform our | 247 // insert the new DownloadItem into 'history_downloads_' or inform our |
248 // observers at this point. OnCreateDatabaseEntryComplete() handles that | 248 // observers at this point. OnCreateDownloadEntryComplete() handles that |
249 // finalization of the the download creation as a callback from the | 249 // finalization of the the download creation as a callback from the |
250 // history thread. | 250 // history thread. |
251 void DownloadManager::StartDownload(DownloadCreateInfo* info) { | 251 void DownloadManager::StartDownload(DownloadCreateInfo* info) { |
252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
253 DCHECK(info); | 253 DCHECK(info); |
254 | 254 |
255 // Check whether this download is for an extension install or not. | 255 // Check whether this download is for an extension install or not. |
256 // Allow extensions to be explicitly saved. | 256 // Allow extensions to be explicitly saved. |
257 if (!info->prompt_user_for_save_location) { | 257 if (!info->prompt_user_for_save_location) { |
258 if (UserScript::HasUserScriptFileExtension(info->url) || | 258 if (UserScript::HasUserScriptFileExtension(info->url) || |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
426 | 426 |
427 DownloadItem* download = new DownloadItem(this, *info, | 427 DownloadItem* download = new DownloadItem(this, *info, |
428 profile_->IsOffTheRecord()); | 428 profile_->IsOffTheRecord()); |
429 DCHECK(!ContainsKey(in_progress_, info->download_id)); | 429 DCHECK(!ContainsKey(in_progress_, info->download_id)); |
430 downloads_.insert(download); | 430 downloads_.insert(download); |
431 } | 431 } |
432 | 432 |
433 void DownloadManager::AttachDownloadItem(DownloadCreateInfo* info, | 433 void DownloadManager::AttachDownloadItem(DownloadCreateInfo* info, |
434 const FilePath& target_path) { | 434 const FilePath& target_path) { |
435 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); | |
436 | |
435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 437 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
436 | 438 |
437 scoped_ptr<DownloadCreateInfo> infop(info); | 439 scoped_ptr<DownloadCreateInfo> infop(info); |
438 info->path = target_path; | 440 info->path = target_path; |
439 | 441 |
440 // NOTE(ahendrickson) We will be adding a new map |active_downloads_|, into | 442 // NOTE(ahendrickson) We will be adding a new map |active_downloads_|, into |
441 // which we will be adding the download as soon as it's created. This will | 443 // which we will be adding the download as soon as it's created. This will |
442 // make this loop unnecessary. | 444 // make this loop unnecessary. |
443 // Eventually |active_downloads_| will replace |in_progress_|, but we don't | 445 // Eventually |active_downloads_| will replace |in_progress_|, but we don't |
444 // want to change the semantics yet. | 446 // want to change the semantics yet. |
445 DCHECK(!ContainsKey(in_progress_, info->download_id)); | 447 DCHECK(!ContainsKey(in_progress_, info->download_id)); |
446 DownloadItem* download = NULL; | 448 DownloadItem* download = NULL; |
447 for (std::set<DownloadItem*>::iterator i = downloads_.begin(); | 449 for (std::set<DownloadItem*>::iterator i = downloads_.begin(); |
448 i != downloads_.end(); ++i) { | 450 i != downloads_.end(); ++i) { |
449 DownloadItem* item = (*i); | 451 DownloadItem* item = (*i); |
450 if (item && (item->id() == info->download_id)) { | 452 if (item && (item->id() == info->download_id)) { |
451 download = item; | 453 download = item; |
452 break; | 454 break; |
453 } | 455 } |
454 } | 456 } |
455 DCHECK(download != NULL); | 457 DCHECK(download != NULL); |
456 download->SetFileCheckResults(info->path, | 458 download->SetFileCheckResults(info->path, |
457 info->is_dangerous, | 459 info->is_dangerous, |
458 info->path_uniquifier, | 460 info->path_uniquifier, |
459 info->prompt_user_for_save_location, | 461 info->prompt_user_for_save_location, |
460 info->is_extension_install, | 462 info->is_extension_install, |
461 info->original_name); | 463 info->original_name); |
462 in_progress_[info->download_id] = download; | 464 in_progress_[info->download_id] = download; |
465 UpdateAppIcon(); // Reflect entry into in_progress_. | |
Paweł Hajdan Jr.
2011/01/03 09:43:03
nit: Just two spaces between code and comment. Ple
Randy Smith (Not in Mondays)
2011/01/04 19:29:21
Done.
| |
463 | 466 |
464 bool download_finished = ContainsKey(pending_finished_downloads_, | 467 // Rename to intermediate name. |
465 info->download_id); | 468 if (info->is_dangerous) { |
466 | 469 // The download is not safe. We can now rename the file to its |
467 VLOG(20) << __FUNCTION__ << "()" | 470 // tentative name using OnFinalDownloadName (the actual final |
468 << " target_path = \"" << target_path.value() << "\"" | 471 // name after user confirmation will be set in |
469 << " download_finished = " << download_finished | 472 // ProceedWithFinishedDangerousDownload). |
470 << " info = " << info->DebugString() | |
471 << " download = " << download->DebugString(true); | |
472 | |
473 if (download_finished || info->is_dangerous) { | |
474 // The download has already finished or the download is not safe. | |
475 // We can now rename the file to its final name (or its tentative name | |
476 // in dangerous download cases). | |
477 BrowserThread::PostTask( | 473 BrowserThread::PostTask( |
478 BrowserThread::FILE, FROM_HERE, | 474 BrowserThread::FILE, FROM_HERE, |
479 NewRunnableMethod( | 475 NewRunnableMethod( |
480 file_manager_, &DownloadFileManager::OnFinalDownloadName, | 476 file_manager_, &DownloadFileManager::OnFinalDownloadName, |
481 download->id(), target_path, !info->is_dangerous, | 477 download->id(), target_path, false, |
482 make_scoped_refptr(this))); | 478 make_scoped_refptr(this))); |
483 } else { | 479 } else { |
484 // The download hasn't finished and it is a safe download. We need to | 480 // The download is a safe download. We need to |
485 // rename it to its intermediate '.crdownload' path. | 481 // rename it to its intermediate '.crdownload' path. The final |
482 // name after user confirmation will be set from | |
483 // DownloadItem::OnSafeDownloadFinished. | |
486 FilePath download_path = download_util::GetCrDownloadPath(target_path); | 484 FilePath download_path = download_util::GetCrDownloadPath(target_path); |
487 BrowserThread::PostTask( | 485 BrowserThread::PostTask( |
488 BrowserThread::FILE, FROM_HERE, | 486 BrowserThread::FILE, FROM_HERE, |
489 NewRunnableMethod( | 487 NewRunnableMethod( |
490 file_manager_, &DownloadFileManager::OnIntermediateDownloadName, | 488 file_manager_, &DownloadFileManager::OnIntermediateDownloadName, |
491 download->id(), download_path, make_scoped_refptr(this))); | 489 download->id(), download_path, make_scoped_refptr(this))); |
492 download->Rename(download_path); | 490 download->Rename(download_path); |
493 } | 491 } |
494 | 492 |
495 if (download_finished) { | |
496 // If the download already completed by the time we reached this point, then | |
497 // notify observers that it did. | |
498 OnAllDataSaved(info->download_id, | |
499 pending_finished_downloads_[info->download_id]); | |
500 } | |
501 | |
502 download_history_->AddEntry(*info, download, | 493 download_history_->AddEntry(*info, download, |
503 NewCallback(this, &DownloadManager::OnCreateDownloadEntryComplete)); | 494 NewCallback(this, &DownloadManager::OnCreateDownloadEntryComplete)); |
504 | |
505 UpdateAppIcon(); | |
506 } | 495 } |
507 | 496 |
508 void DownloadManager::UpdateDownload(int32 download_id, int64 size) { | 497 void DownloadManager::UpdateDownload(int32 download_id, int64 size) { |
509 DownloadMap::iterator it = in_progress_.find(download_id); | 498 DownloadMap::iterator it = in_progress_.find(download_id); |
510 if (it != in_progress_.end()) { | 499 if (it != in_progress_.end()) { |
511 DownloadItem* download = it->second; | 500 DownloadItem* download = it->second; |
512 download->Update(size); | 501 download->Update(size); |
513 download_history_->UpdateEntry(download); | 502 download_history_->UpdateEntry(download); |
503 UpdateAppIcon(); // Reflect size update. | |
514 } | 504 } |
515 UpdateAppIcon(); | |
516 } | 505 } |
517 | 506 |
518 void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) { | 507 void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) { |
519 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id | 508 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id |
520 << " size = " << size; | 509 << " size = " << size; |
521 DownloadMap::iterator it = in_progress_.find(download_id); | 510 |
522 if (it == in_progress_.end()) { | 511 DCHECK_EQ(pending_finished_downloads_.count(download_id), 0U); |
Paweł Hajdan Jr.
2011/01/03 09:43:03
nit: 0U should be first parameter (convention).
Randy Smith (Not in Mondays)
2011/01/04 19:29:21
Done.
| |
523 // The download is done, but the user hasn't selected a final location for | 512 pending_finished_downloads_[download_id] = size; |
524 // it yet (the Save As dialog box is probably still showing), so just keep | 513 |
525 // track of the fact that this download id is complete, when the | 514 MaybeCompleteDownload(download_id, size); |
526 // DownloadItem is constructed later we'll notify its completion then. | 515 } |
527 PendingFinishedMap::iterator erase_it = | 516 |
528 pending_finished_downloads_.find(download_id); | 517 void DownloadManager::MaybeCompleteDownload(int32 download_id, int64 size) { |
529 DCHECK(erase_it == pending_finished_downloads_.end()); | 518 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id; |
530 pending_finished_downloads_[download_id] = size; | 519 |
531 VLOG(20) << __FUNCTION__ << "()" << " Added download_id = " << download_id | 520 // Only complete the download if we've received all the data AND |
532 << " to pending_finished_downloads_"; | 521 // we've completed all UI initialization. |
522 if (!(pending_finished_downloads_.count(download_id) != 0 && | |
Paweł Hajdan Jr.
2011/01/03 09:43:03
Can we extract this logic to a separate method?
Randy Smith (Not in Mondays)
2011/01/04 19:29:21
Done.
| |
523 in_progress_.count(download_id) != 0 && | |
524 (in_progress_[download_id]->db_handle() != | |
525 DownloadHistory::kUninitializedHandle))) { | |
533 return; | 526 return; |
534 } | 527 } |
535 | 528 |
536 // Remove the id from the list of pending ids. | 529 // Confirm we're in the proper set of states to be here; |
537 PendingFinishedMap::iterator erase_it = | 530 // in in_progress_, in pending_finished_, have a history handle. |
538 pending_finished_downloads_.find(download_id); | 531 DCHECK(in_progress_.count(download_id) == 1); |
Paweł Hajdan Jr.
2011/01/03 09:43:03
nit: DCHECK_EQ?
Randy Smith (Not in Mondays)
2011/01/04 19:29:21
Done.
| |
539 if (erase_it != pending_finished_downloads_.end()) { | 532 DCHECK(pending_finished_downloads_.count(download_id) == 1); |
Paweł Hajdan Jr.
2011/01/03 09:43:03
nit: DCHECK_EQ?
Randy Smith (Not in Mondays)
2011/01/04 19:29:21
Done.
| |
540 pending_finished_downloads_.erase(erase_it); | 533 DownloadItem* download = in_progress_[download_id]; |
541 VLOG(20) << __FUNCTION__ << "()" << " Removed download_id = " << download_id | 534 DCHECK(download->db_handle() != DownloadHistory::kUninitializedHandle); |
542 << " from pending_finished_downloads_"; | 535 DCHECK(history_downloads_.count(download->db_handle()) == 1); |
Paweł Hajdan Jr.
2011/01/03 09:43:03
nit: DCHECK_EQ?
Randy Smith (Not in Mondays)
2011/01/04 19:29:21
Done.
| |
536 | |
537 VLOG(20) << __FUNCTION__ << "()" << " executing: download = " | |
538 << download->DebugString(false); | |
539 | |
540 // Remove the id from in_progress and pending_finished. | |
541 pending_finished_downloads_.erase(download_id); | |
542 in_progress_.erase(download_id); | |
543 UpdateAppIcon(); // Reflect removal from in_progress_. | |
544 | |
545 // Final update of download item and history. | |
546 download->OnAllDataSaved(size); | |
547 download_history_->UpdateEntry(download); | |
548 | |
549 switch (download->safety_state()) { | |
550 case DownloadItem::DANGEROUS: | |
551 // If this a dangerous download not yet validated by the user, don't do | |
552 // anything. When the user notifies us, it will trigger a call to | |
553 // ProceedWithFinishedDangerousDownload. | |
554 return; | |
555 case DownloadItem::DANGEROUS_BUT_VALIDATED: | |
556 // The dangerous download has been validated by the user. We first | |
557 // need to rename the downloaded file from its temporary name to | |
558 // its final name. We will continue the download processing in the | |
559 // callback. | |
560 BrowserThread::PostTask( | |
561 BrowserThread::FILE, FROM_HERE, | |
562 NewRunnableMethod( | |
563 this, &DownloadManager::ProceedWithFinishedDangerousDownload, | |
564 download->db_handle(), | |
565 download->full_path(), download->target_name())); | |
566 return; | |
567 case DownloadItem::SAFE: | |
568 // The download is safe; just finish it. | |
569 download->OnSafeDownloadFinished(file_manager_); | |
570 return; | |
543 } | 571 } |
544 | |
545 DownloadItem* download = it->second; | |
546 | |
547 VLOG(20) << __FUNCTION__ << "()" | |
548 << " download = " << download->DebugString(true); | |
549 | |
550 download->OnAllDataSaved(size); | |
551 | |
552 // Clean up will happen when the history system create callback runs if we | |
553 // don't have a valid db_handle yet. | |
554 if (download->db_handle() != DownloadHistory::kUninitializedHandle) { | |
555 in_progress_.erase(it); | |
556 download_history_->UpdateEntry(download); | |
557 } | |
558 | |
559 UpdateAppIcon(); | |
560 | |
561 // If this a dangerous download not yet validated by the user, don't do | |
562 // anything. When the user notifies us, it will trigger a call to | |
563 // ProceedWithFinishedDangerousDownload. | |
564 if (download->safety_state() == DownloadItem::DANGEROUS) { | |
565 return; | |
566 } | |
567 | |
568 if (download->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED) { | |
569 // We first need to rename the downloaded file from its temporary name to | |
570 // its final name before we can continue. | |
571 BrowserThread::PostTask( | |
572 BrowserThread::FILE, FROM_HERE, | |
573 NewRunnableMethod( | |
574 this, &DownloadManager::ProceedWithFinishedDangerousDownload, | |
575 download->db_handle(), | |
576 download->full_path(), download->target_name())); | |
577 return; | |
578 } | |
579 | |
580 download->OnSafeDownloadFinished(file_manager_); | |
581 } | 572 } |
582 | 573 |
583 void DownloadManager::DownloadRenamedToFinalName(int download_id, | 574 void DownloadManager::DownloadRenamedToFinalName(int download_id, |
584 const FilePath& full_path) { | 575 const FilePath& full_path) { |
585 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id | 576 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id |
586 << " full_path = \"" << full_path.value() << "\""; | 577 << " full_path = \"" << full_path.value() << "\""; |
587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
588 DownloadItem* item = GetDownloadItem(download_id); | 579 DownloadItem* item = GetDownloadItem(download_id); |
589 if (!item) | 580 if (!item) |
590 return; | 581 return; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
654 return; | 645 return; |
655 DownloadItem* download = it->second; | 646 DownloadItem* download = it->second; |
656 | 647 |
657 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id | 648 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id |
658 << " download = " << download->DebugString(true); | 649 << " download = " << download->DebugString(true); |
659 | 650 |
660 // Clean up will happen when the history system create callback runs if we | 651 // Clean up will happen when the history system create callback runs if we |
661 // don't have a valid db_handle yet. | 652 // don't have a valid db_handle yet. |
662 if (download->db_handle() != DownloadHistory::kUninitializedHandle) { | 653 if (download->db_handle() != DownloadHistory::kUninitializedHandle) { |
663 in_progress_.erase(it); | 654 in_progress_.erase(it); |
655 UpdateAppIcon(); // Reflect removal from in_progress_. | |
664 download_history_->UpdateEntry(download); | 656 download_history_->UpdateEntry(download); |
665 } | 657 } |
666 | 658 |
667 DownloadCancelledInternal(download_id, | 659 DownloadCancelledInternal(download_id, |
668 download->render_process_id(), | 660 download->render_process_id(), |
669 download->request_id()); | 661 download->request_id()); |
670 UpdateAppIcon(); | |
671 } | 662 } |
672 | 663 |
673 void DownloadManager::DownloadCancelledInternal(int download_id, | 664 void DownloadManager::DownloadCancelledInternal(int download_id, |
674 int render_process_id, | 665 int render_process_id, |
675 int request_id) { | 666 int request_id) { |
676 // Cancel the network request. RDH is guaranteed to outlive the IO thread. | 667 // Cancel the network request. RDH is guaranteed to outlive the IO thread. |
677 BrowserThread::PostTask( | 668 BrowserThread::PostTask( |
678 BrowserThread::IO, FROM_HERE, | 669 BrowserThread::IO, FROM_HERE, |
679 NewRunnableFunction(&download_util::CancelDownloadRequest, | 670 NewRunnableFunction(&download_util::CancelDownloadRequest, |
680 g_browser_process->resource_dispatcher_host(), | 671 g_browser_process->resource_dispatcher_host(), |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
982 DCHECK(history_downloads_.find(download->db_handle()) == | 973 DCHECK(history_downloads_.find(download->db_handle()) == |
983 history_downloads_.end()); | 974 history_downloads_.end()); |
984 history_downloads_[download->db_handle()] = download; | 975 history_downloads_[download->db_handle()] = download; |
985 | 976 |
986 // Show in the appropropriate browser UI. | 977 // Show in the appropropriate browser UI. |
987 ShowDownloadInBrowser(info, download); | 978 ShowDownloadInBrowser(info, download); |
988 | 979 |
989 // Inform interested objects about the new download. | 980 // Inform interested objects about the new download. |
990 NotifyModelChanged(); | 981 NotifyModelChanged(); |
991 | 982 |
992 // If this download has been completed before we've received the db handle, | 983 // If this download has been cancelled before we've received the DB handle, |
993 // post one final message to the history service so that it can be properly | 984 // post one final message to the history service so that it can be properly |
994 // in sync with the DownloadItem's completion status, and also inform any | 985 // in sync with the DownloadItem's completion status, and also inform any |
995 // observers so that they get more than just the start notification. | 986 // observers so that they get more than just the start notification. |
987 // | |
988 // Otherwise, try to complete the download | |
996 if (download->state() != DownloadItem::IN_PROGRESS) { | 989 if (download->state() != DownloadItem::IN_PROGRESS) { |
990 DCHECK(download->state() == DownloadItem::CANCELLED); | |
997 in_progress_.erase(it); | 991 in_progress_.erase(it); |
998 download_history_->UpdateEntry(download); | 992 download_history_->UpdateEntry(download); |
999 download->UpdateObservers(); | 993 download->UpdateObservers(); |
994 } else { | |
995 MaybeCompleteDownload(info.download_id, | |
996 pending_finished_downloads_[info.download_id]); | |
1000 } | 997 } |
1001 | |
1002 UpdateAppIcon(); | |
1003 } | 998 } |
1004 | 999 |
1005 void DownloadManager::ShowDownloadInBrowser(const DownloadCreateInfo& info, | 1000 void DownloadManager::ShowDownloadInBrowser(const DownloadCreateInfo& info, |
1006 DownloadItem* download) { | 1001 DownloadItem* download) { |
1007 // The 'contents' may no longer exist if the user closed the tab before we | 1002 // The 'contents' may no longer exist if the user closed the tab before we |
1008 // get this start completion event. If it does, tell the origin TabContents | 1003 // get this start completion event. If it does, tell the origin TabContents |
1009 // to display its download shelf. | 1004 // to display its download shelf. |
1010 TabContents* contents = tab_util::GetTabContentsByID(info.child_id, | 1005 TabContents* contents = tab_util::GetTabContentsByID(info.child_id, |
1011 info.render_view_id); | 1006 info.render_view_id); |
1012 | 1007 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1108 observed_download_manager_->RemoveObserver(this); | 1103 observed_download_manager_->RemoveObserver(this); |
1109 } | 1104 } |
1110 | 1105 |
1111 void DownloadManager::OtherDownloadManagerObserver::ModelChanged() { | 1106 void DownloadManager::OtherDownloadManagerObserver::ModelChanged() { |
1112 observing_download_manager_->NotifyModelChanged(); | 1107 observing_download_manager_->NotifyModelChanged(); |
1113 } | 1108 } |
1114 | 1109 |
1115 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { | 1110 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { |
1116 observed_download_manager_ = NULL; | 1111 observed_download_manager_ = NULL; |
1117 } | 1112 } |
OLD | NEW |