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_. | |
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(0U, pending_finished_downloads_.count(download_id)); |
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 bool DownloadManager::DownloadReadyForCompletion(int32 download_id) { |
529 DCHECK(erase_it == pending_finished_downloads_.end()); | 518 // Have we both gotten all the data for the download and completed |
530 pending_finished_downloads_[download_id] = size; | 519 // all preperatory processing on it? The preperatory |
531 VLOG(20) << __FUNCTION__ << "()" << " Added download_id = " << download_id | 520 // processing consists of file name determination, |
532 << " to pending_finished_downloads_"; | 521 // intermediate file rename, UI display, and history insertion. It is |
522 // linear, so we can simply check for history insertion. | |
Paweł Hajdan Jr.
2011/01/05 07:46:30
Can you DCHECK that this assumption is valid? This
Randy Smith (Not in Mondays)
2011/01/13 02:13:24
It's going to be heavily refactored to make it mor
| |
523 return | |
Paweł Hajdan Jr.
2011/01/05 07:46:30
nit: This is a bit complicated, so maybe we can co
Randy Smith (Not in Mondays)
2011/01/13 02:13:24
Done.
| |
524 (pending_finished_downloads_.count(download_id) != 0 && | |
525 in_progress_.count(download_id) != 0 && | |
526 (in_progress_[download_id]->db_handle() != | |
527 DownloadHistory::kUninitializedHandle)); | |
528 } | |
529 | |
530 void DownloadManager::MaybeCompleteDownload(int32 download_id, int64 size) { | |
531 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id; | |
532 | |
533 if (!DownloadReadyForCompletion(download_id)) | |
533 return; | 534 return; |
535 | |
536 // Confirm we're in the proper set of states to be here; | |
537 // in in_progress_, in pending_finished_, have a history handle. | |
538 DCHECK_EQ(1u, in_progress_.count(download_id)); | |
539 DCHECK_EQ(1u, pending_finished_downloads_.count(download_id)); | |
540 DownloadItem* download = in_progress_[download_id]; | |
541 DCHECK(download->db_handle() != DownloadHistory::kUninitializedHandle); | |
542 DCHECK_EQ(1u, history_downloads_.count(download->db_handle())); | |
543 | |
544 VLOG(20) << __FUNCTION__ << "()" << " executing: download = " | |
545 << download->DebugString(false); | |
546 | |
547 // Remove the id from in_progress and pending_finished. | |
548 pending_finished_downloads_.erase(download_id); | |
549 in_progress_.erase(download_id); | |
550 UpdateAppIcon(); // Reflect removal from in_progress_. | |
551 | |
552 // Final update of download item and history. | |
553 download->OnAllDataSaved(size); | |
554 download_history_->UpdateEntry(download); | |
555 | |
556 switch (download->safety_state()) { | |
557 case DownloadItem::DANGEROUS: | |
558 // If this a dangerous download not yet validated by the user, don't do | |
559 // anything. When the user notifies us, it will trigger a call to | |
560 // ProceedWithFinishedDangerousDownload. | |
561 return; | |
562 case DownloadItem::DANGEROUS_BUT_VALIDATED: | |
563 // The dangerous download has been validated by the user. We first | |
564 // need to rename the downloaded file from its temporary name to | |
565 // its final name. We will continue the download processing in the | |
566 // callback. | |
567 BrowserThread::PostTask( | |
568 BrowserThread::FILE, FROM_HERE, | |
569 NewRunnableMethod( | |
570 this, &DownloadManager::ProceedWithFinishedDangerousDownload, | |
571 download->db_handle(), | |
572 download->full_path(), download->target_name())); | |
573 return; | |
574 case DownloadItem::SAFE: | |
575 // The download is safe; just finish it. | |
576 download->OnSafeDownloadFinished(file_manager_); | |
577 return; | |
534 } | 578 } |
535 | |
536 // Remove the id from the list of pending ids. | |
537 PendingFinishedMap::iterator erase_it = | |
538 pending_finished_downloads_.find(download_id); | |
539 if (erase_it != pending_finished_downloads_.end()) { | |
540 pending_finished_downloads_.erase(erase_it); | |
541 VLOG(20) << __FUNCTION__ << "()" << " Removed download_id = " << download_id | |
542 << " from pending_finished_downloads_"; | |
543 } | |
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 } | 579 } |
582 | 580 |
583 void DownloadManager::DownloadRenamedToFinalName(int download_id, | 581 void DownloadManager::DownloadRenamedToFinalName(int download_id, |
584 const FilePath& full_path) { | 582 const FilePath& full_path) { |
585 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id | 583 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id |
586 << " full_path = \"" << full_path.value() << "\""; | 584 << " full_path = \"" << full_path.value() << "\""; |
587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 585 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
588 DownloadItem* item = GetDownloadItem(download_id); | 586 DownloadItem* item = GetDownloadItem(download_id); |
589 if (!item) | 587 if (!item) |
590 return; | 588 return; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
654 return; | 652 return; |
655 DownloadItem* download = it->second; | 653 DownloadItem* download = it->second; |
656 | 654 |
657 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id | 655 VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id |
658 << " download = " << download->DebugString(true); | 656 << " download = " << download->DebugString(true); |
659 | 657 |
660 // Clean up will happen when the history system create callback runs if we | 658 // Clean up will happen when the history system create callback runs if we |
661 // don't have a valid db_handle yet. | 659 // don't have a valid db_handle yet. |
662 if (download->db_handle() != DownloadHistory::kUninitializedHandle) { | 660 if (download->db_handle() != DownloadHistory::kUninitializedHandle) { |
663 in_progress_.erase(it); | 661 in_progress_.erase(it); |
662 UpdateAppIcon(); // Reflect removal from in_progress_. | |
664 download_history_->UpdateEntry(download); | 663 download_history_->UpdateEntry(download); |
665 } | 664 } |
666 | 665 |
667 DownloadCancelledInternal(download_id, | 666 DownloadCancelledInternal(download_id, |
668 download->render_process_id(), | 667 download->render_process_id(), |
669 download->request_id()); | 668 download->request_id()); |
670 UpdateAppIcon(); | |
671 } | 669 } |
672 | 670 |
673 void DownloadManager::DownloadCancelledInternal(int download_id, | 671 void DownloadManager::DownloadCancelledInternal(int download_id, |
674 int render_process_id, | 672 int render_process_id, |
675 int request_id) { | 673 int request_id) { |
676 // Cancel the network request. RDH is guaranteed to outlive the IO thread. | 674 // Cancel the network request. RDH is guaranteed to outlive the IO thread. |
677 BrowserThread::PostTask( | 675 BrowserThread::PostTask( |
678 BrowserThread::IO, FROM_HERE, | 676 BrowserThread::IO, FROM_HERE, |
679 NewRunnableFunction(&download_util::CancelDownloadRequest, | 677 NewRunnableFunction(&download_util::CancelDownloadRequest, |
680 g_browser_process->resource_dispatcher_host(), | 678 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()) == | 980 DCHECK(history_downloads_.find(download->db_handle()) == |
983 history_downloads_.end()); | 981 history_downloads_.end()); |
984 history_downloads_[download->db_handle()] = download; | 982 history_downloads_[download->db_handle()] = download; |
985 | 983 |
986 // Show in the appropropriate browser UI. | 984 // Show in the appropropriate browser UI. |
987 ShowDownloadInBrowser(info, download); | 985 ShowDownloadInBrowser(info, download); |
988 | 986 |
989 // Inform interested objects about the new download. | 987 // Inform interested objects about the new download. |
990 NotifyModelChanged(); | 988 NotifyModelChanged(); |
991 | 989 |
992 // If this download has been completed before we've received the db handle, | 990 // 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 | 991 // 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 | 992 // in sync with the DownloadItem's completion status, and also inform any |
995 // observers so that they get more than just the start notification. | 993 // observers so that they get more than just the start notification. |
994 // | |
995 // Otherwise, try to complete the download | |
996 if (download->state() != DownloadItem::IN_PROGRESS) { | 996 if (download->state() != DownloadItem::IN_PROGRESS) { |
997 DCHECK_EQ(DownloadItem::CANCELLED, download->state()); | |
997 in_progress_.erase(it); | 998 in_progress_.erase(it); |
998 download_history_->UpdateEntry(download); | 999 download_history_->UpdateEntry(download); |
999 download->UpdateObservers(); | 1000 download->UpdateObservers(); |
1001 } else { | |
1002 MaybeCompleteDownload(info.download_id, | |
1003 pending_finished_downloads_[info.download_id]); | |
1000 } | 1004 } |
1001 | |
1002 UpdateAppIcon(); | |
1003 } | 1005 } |
1004 | 1006 |
1005 void DownloadManager::ShowDownloadInBrowser(const DownloadCreateInfo& info, | 1007 void DownloadManager::ShowDownloadInBrowser(const DownloadCreateInfo& info, |
1006 DownloadItem* download) { | 1008 DownloadItem* download) { |
1007 // The 'contents' may no longer exist if the user closed the tab before we | 1009 // 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 | 1010 // get this start completion event. If it does, tell the origin TabContents |
1009 // to display its download shelf. | 1011 // to display its download shelf. |
1010 TabContents* contents = tab_util::GetTabContentsByID(info.child_id, | 1012 TabContents* contents = tab_util::GetTabContentsByID(info.child_id, |
1011 info.render_view_id); | 1013 info.render_view_id); |
1012 | 1014 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1108 observed_download_manager_->RemoveObserver(this); | 1110 observed_download_manager_->RemoveObserver(this); |
1109 } | 1111 } |
1110 | 1112 |
1111 void DownloadManager::OtherDownloadManagerObserver::ModelChanged() { | 1113 void DownloadManager::OtherDownloadManagerObserver::ModelChanged() { |
1112 observing_download_manager_->NotifyModelChanged(); | 1114 observing_download_manager_->NotifyModelChanged(); |
1113 } | 1115 } |
1114 | 1116 |
1115 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { | 1117 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { |
1116 observed_download_manager_ = NULL; | 1118 observed_download_manager_ = NULL; |
1117 } | 1119 } |
OLD | NEW |