Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: content/browser/download/download_manager_impl.cc

Issue 10704052: Download filename determination refactor (3/3) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/browser/download/download_manager_impl.h" 5 #include "content/browser/download/download_manager_impl.h"
6 6
7 #include <iterator> 7 #include <iterator>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 if (delegate_) 237 if (delegate_)
238 id = delegate_->GetNextId(); 238 id = delegate_->GetNextId();
239 if (!id.IsValid()) { 239 if (!id.IsValid()) {
240 static int next_id; 240 static int next_id;
241 id = DownloadId(browser_context_, ++next_id); 241 id = DownloadId(browser_context_, ++next_id);
242 } 242 }
243 243
244 return id; 244 return id;
245 } 245 }
246 246
247 DownloadFileManager* DownloadManagerImpl::GetDownloadFileManager() {
248 return file_manager_;
249 }
250
247 bool DownloadManagerImpl::ShouldOpenDownload(DownloadItemImpl* item) { 251 bool DownloadManagerImpl::ShouldOpenDownload(DownloadItemImpl* item) {
248 if (!delegate_) 252 if (!delegate_)
249 return true; 253 return true;
250 254
251 return delegate_->ShouldOpenDownload(item); 255 return delegate_->ShouldOpenDownload(item);
252 } 256 }
253 257
254 bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) { 258 bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
255 if (!delegate_) 259 if (!delegate_)
256 return false; 260 return false;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 328
325 active_downloads_.clear(); 329 active_downloads_.clear();
326 STLDeleteValues(&downloads_to_delete); 330 STLDeleteValues(&downloads_to_delete);
327 331
328 // We'll have nothing more to report to the observers after this point. 332 // We'll have nothing more to report to the observers after this point.
329 observers_.Clear(); 333 observers_.Clear();
330 334
331 file_manager_ = NULL; 335 file_manager_ = NULL;
332 if (delegate_) 336 if (delegate_)
333 delegate_->Shutdown(); 337 delegate_->Shutdown();
338 delegate_ = NULL;
334 } 339 }
335 340
336 void DownloadManagerImpl::GetTemporaryDownloads( 341 void DownloadManagerImpl::GetTemporaryDownloads(
337 const FilePath& dir_path, DownloadVector* result) { 342 const FilePath& dir_path, DownloadVector* result) {
338 DCHECK(result); 343 DCHECK(result);
339 344
340 for (DownloadMap::iterator it = downloads_.begin(); 345 for (DownloadMap::iterator it = downloads_.begin();
341 it != downloads_.end(); ++it) { 346 it != downloads_.end(); ++it) {
342 DownloadItemImpl* item = it->second; 347 DownloadItemImpl* item = it->second;
343 // TODO(benjhayden): Don't check IsPersisted(). 348 // TODO(benjhayden): Don't check IsPersisted().
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 OnDownloadInterrupted(download_id, reason); 436 OnDownloadInterrupted(download_id, reason);
432 // TODO(rdsmith): It makes no sense to continue along the 437 // TODO(rdsmith): It makes no sense to continue along the
433 // regular download path after we've gotten an error. But it's 438 // regular download path after we've gotten an error. But it's
434 // the way the code has historically worked, and this allows us 439 // the way the code has historically worked, and this allows us
435 // to get the download persisted and observers of the download manager 440 // to get the download persisted and observers of the download manager
436 // notified, so tests work. When we execute all side effects of cancel 441 // notified, so tests work. When we execute all side effects of cancel
437 // (including queue removal) immedately rather than waiting for 442 // (including queue removal) immedately rather than waiting for
438 // persistence we should replace this comment with a "return;". 443 // persistence we should replace this comment with a "return;".
439 } 444 }
440 445
441 if (!delegate_ || delegate_->ShouldStartDownload(download_id)) 446 DownloadMap::iterator download_iter = active_downloads_.find(download_id);
442 RestartDownload(download_id); 447 if (download_iter == active_downloads_.end())
448 return;
449
450 DownloadItemImpl* download = download_iter->second;
451 content::DownloadTargetCallback callback =
452 base::Bind(&DownloadManagerImpl::OnDownloadTargetDetermined,
453 this, download_id);
454 if (!delegate_ || !delegate_->DetermineDownloadTarget(download, callback)) {
455 FilePath target_path = download->GetForcedFilePath();
456 // TODO(asanka): Determine a useful path if |target_path| is empty.
457 callback.Run(target_path,
458 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
459 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
460 target_path);
461 }
462 }
463
464 void DownloadManagerImpl::OnDownloadTargetDetermined(
465 int32 download_id,
466 const FilePath& target_path,
467 DownloadItem::TargetDisposition disposition,
468 content::DownloadDangerType danger_type,
469 const FilePath& intermediate_path) {
470 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
471 DownloadMap::iterator download_iter = active_downloads_.find(download_id);
472 if (download_iter != active_downloads_.end()) {
473 // Once DownloadItem::OnDownloadTargetDetermined() is called, we expect a
474 // DownloadRenamedToIntermediateName() callback. This is necessary for the
475 // download to proceed.
476 download_iter->second->OnDownloadTargetDetermined(
477 target_path, disposition, danger_type, intermediate_path);
478 }
443 } 479 }
444 480
445 void DownloadManagerImpl::CheckForHistoryFilesRemoval() { 481 void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
446 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
447 for (DownloadMap::iterator it = downloads_.begin(); 483 for (DownloadMap::iterator it = downloads_.begin();
448 it != downloads_.end(); ++it) { 484 it != downloads_.end(); ++it) {
449 DownloadItemImpl* item = it->second; 485 DownloadItemImpl* item = it->second;
450 if (item->IsPersisted()) 486 if (item->IsPersisted())
451 CheckForFileRemoval(item); 487 CheckForFileRemoval(item);
452 } 488 }
(...skipping 22 matching lines...) Expand all
475 download_id)); 511 download_id));
476 } 512 }
477 } 513 }
478 514
479 void DownloadManagerImpl::OnFileRemovalDetected(int32 download_id) { 515 void DownloadManagerImpl::OnFileRemovalDetected(int32 download_id) {
480 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
481 if (ContainsKey(downloads_, download_id)) 517 if (ContainsKey(downloads_, download_id))
482 downloads_[download_id]->OnDownloadedFileRemoved(); 518 downloads_[download_id]->OnDownloadedFileRemoved();
483 } 519 }
484 520
485 void DownloadManagerImpl::RestartDownload(int32 download_id) {
486 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
487
488 if (!ContainsKey(active_downloads_, download_id))
489 return;
490 DownloadItemImpl* download = active_downloads_[download_id];
491
492 VLOG(20) << __FUNCTION__ << "()"
493 << " download = " << download->DebugString(true);
494
495 if (download->GetTargetDisposition() ==
496 DownloadItem::TARGET_DISPOSITION_PROMPT) {
497 // We must ask the user for the place to put the download.
498 if (delegate_) {
499 delegate_->ChooseDownloadPath(download);
500 FOR_EACH_OBSERVER(Observer, observers_,
501 SelectFileDialogDisplayed(this, download_id));
502 } else {
503 FileSelectionCanceled(download_id);
504 }
505 } else {
506 // No prompting for download, just continue with the current target path.
507 OnTargetPathAvailable(download);
508 }
509 }
510
511 content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const { 521 content::BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
512 return browser_context_; 522 return browser_context_;
513 } 523 }
514 524
515 FilePath DownloadManagerImpl::LastDownloadPath() {
516 return last_download_path_;
517 }
518
519 net::BoundNetLog DownloadManagerImpl::CreateDownloadItem( 525 net::BoundNetLog DownloadManagerImpl::CreateDownloadItem(
520 DownloadCreateInfo* info) { 526 DownloadCreateInfo* info) {
521 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 527 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
522 528
523 net::BoundNetLog bound_net_log = 529 net::BoundNetLog bound_net_log =
524 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD); 530 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
525 if (!info->download_id.IsValid()) 531 if (!info->download_id.IsValid())
526 info->download_id = GetNextId(); 532 info->download_id = GetNextId();
527 DownloadItemImpl* download = factory_->CreateActiveItem( 533 DownloadItemImpl* download = factory_->CreateActiveItem(
528 this, *info, 534 this, *info,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 new SavePageExternalData(download); 569 new SavePageExternalData(download);
564 DCHECK(SavePageExternalData::Get(download)); 570 DCHECK(SavePageExternalData::Get(download));
565 571
566 // Will notify the observer in the callback. 572 // Will notify the observer in the callback.
567 if (delegate_) 573 if (delegate_)
568 delegate_->AddItemToPersistentStore(download); 574 delegate_->AddItemToPersistentStore(download);
569 575
570 return download; 576 return download;
571 } 577 }
572 578
573 // The target path for the download item is now valid. We proceed with the
574 // determination of an intermediate path.
575 void DownloadManagerImpl::OnTargetPathAvailable(DownloadItemImpl* download) {
576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
577 DCHECK(download);
578 DCHECK(ContainsKey(downloads_, download->GetId()));
579 DCHECK(ContainsKey(active_downloads_, download->GetId()));
580
581 VLOG(20) << __FUNCTION__ << "()"
582 << " download = " << download->DebugString(true);
583
584 // Rename to intermediate name.
585 // TODO(asanka): Skip this rename if download->AllDataSaved() is true. This
586 // avoids a spurious rename when we can just rename to the final
587 // filename. Unnecessary renames may cause bugs like
588 // http://crbug.com/74187.
589 FilePath intermediate_path;
590 if (delegate_)
591 intermediate_path = delegate_->GetIntermediatePath(*download);
592 else
593 intermediate_path = download->GetTargetFilePath();
594
595 // We want the intermediate and target paths to refer to the same directory so
596 // that they are both on the same device and subject to same
597 // space/permission/availability constraints.
598 DCHECK(intermediate_path.DirName() ==
599 download->GetTargetFilePath().DirName());
600 download->OnIntermediatePathDetermined(file_manager_, intermediate_path);
601 }
602
603 void DownloadManagerImpl::UpdateDownload(int32 download_id, 579 void DownloadManagerImpl::UpdateDownload(int32 download_id,
604 int64 bytes_so_far, 580 int64 bytes_so_far,
605 int64 bytes_per_sec, 581 int64 bytes_per_sec,
606 const std::string& hash_state) { 582 const std::string& hash_state) {
607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
608 DownloadMap::iterator it = active_downloads_.find(download_id); 584 DownloadMap::iterator it = active_downloads_.find(download_id);
609 if (it != active_downloads_.end()) { 585 if (it != active_downloads_.end()) {
610 DownloadItemImpl* download = it->second; 586 DownloadItemImpl* download = it->second;
611 if (download->IsInProgress()) { 587 if (download->IsInProgress()) {
612 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state); 588 download->UpdateProgress(bytes_so_far, bytes_per_sec, hash_state);
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 if (delegate_ && !delegate_->ShouldCompleteDownload(download, base::Bind( 697 if (delegate_ && !delegate_->ShouldCompleteDownload(download, base::Bind(
722 &DownloadManagerImpl::MaybeCompleteDownloadById, 698 &DownloadManagerImpl::MaybeCompleteDownloadById,
723 this, download->GetId()))) 699 this, download->GetId())))
724 return; 700 return;
725 701
726 VLOG(20) << __FUNCTION__ << "()" << " executing: download = " 702 VLOG(20) << __FUNCTION__ << "()" << " executing: download = "
727 << download->DebugString(false); 703 << download->DebugString(false);
728 704
729 if (delegate_) 705 if (delegate_)
730 delegate_->UpdateItemInPersistentStore(download); 706 delegate_->UpdateItemInPersistentStore(download);
731 download->OnDownloadCompleting(file_manager_); 707 download->OnDownloadCompleting();
732 } 708 }
733 709
734 void DownloadManagerImpl::MaybeCompleteDownloadById(int download_id) { 710 void DownloadManagerImpl::MaybeCompleteDownloadById(int download_id) {
735 if (ContainsKey(active_downloads_, download_id)) 711 if (ContainsKey(active_downloads_, download_id))
736 MaybeCompleteDownload(active_downloads_[download_id]); 712 MaybeCompleteDownload(active_downloads_[download_id]);
737 } 713 }
738 714
739 void DownloadManagerImpl::DownloadCompleted(DownloadItemImpl* download) { 715 void DownloadManagerImpl::DownloadCompleted(DownloadItemImpl* download) {
740 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 716 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
741 DCHECK(download); 717 DCHECK(download);
(...skipping 15 matching lines...) Expand all
757 733
758 VLOG(20) << __FUNCTION__ << "()" 734 VLOG(20) << __FUNCTION__ << "()"
759 << " download = " << download->DebugString(true); 735 << " download = " << download->DebugString(true);
760 736
761 RemoveFromActiveList(download); 737 RemoveFromActiveList(download);
762 // This function is called from the DownloadItem, so DI state 738 // This function is called from the DownloadItem, so DI state
763 // should already have been updated. 739 // should already have been updated.
764 AssertStateConsistent(download); 740 AssertStateConsistent(download);
765 741
766 DCHECK(file_manager_); 742 DCHECK(file_manager_);
767 download->OffThreadCancel(file_manager_); 743 download->OffThreadCancel();
768 } 744 }
769 745
770 void DownloadManagerImpl::OnDownloadInterrupted( 746 void DownloadManagerImpl::OnDownloadInterrupted(
771 int32 download_id, 747 int32 download_id,
772 content::DownloadInterruptReason reason) { 748 content::DownloadInterruptReason reason) {
773 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 749 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
774 750
775 if (!ContainsKey(active_downloads_, download_id)) 751 if (!ContainsKey(active_downloads_, download_id))
776 return; 752 return;
777 active_downloads_[download_id]->Interrupt(reason); 753 active_downloads_[download_id]->Interrupt(reason);
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
886 // TODO: It is the responsibility of the observers to query the 862 // TODO: It is the responsibility of the observers to query the
887 // DownloadManager. Remove the following call from here and update all 863 // DownloadManager. Remove the following call from here and update all
888 // observers. 864 // observers.
889 observer->ModelChanged(this); 865 observer->ModelChanged(this);
890 } 866 }
891 867
892 void DownloadManagerImpl::RemoveObserver(Observer* observer) { 868 void DownloadManagerImpl::RemoveObserver(Observer* observer) {
893 observers_.RemoveObserver(observer); 869 observers_.RemoveObserver(observer);
894 } 870 }
895 871
896 void DownloadManagerImpl::FileSelected(const FilePath& path,
897 int32 download_id) {
898 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
899 DCHECK(!path.empty());
900
901 if (!ContainsKey(active_downloads_, download_id))
902 return;
903 DownloadItemImpl* download = active_downloads_[download_id];
904
905 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\""
906 << " download = " << download->DebugString(true);
907
908 // Retain the last directory. Exclude temporary downloads since the path
909 // likely points at the location of a temporary file.
910 if (!download->IsTemporary())
911 last_download_path_ = path.DirName();
912
913 // Make sure the initial file name is set only once.
914 download->OnTargetPathSelected(path);
915 OnTargetPathAvailable(download);
916 }
917
918 void DownloadManagerImpl::FileSelectionCanceled(int32 download_id) {
919 // The user didn't pick a place to save the file, so need to cancel the
920 // download that's already in progress to the temporary location.
921 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
922
923 if (!ContainsKey(active_downloads_, download_id))
924 return;
925 DownloadItemImpl* download = active_downloads_[download_id];
926
927 VLOG(20) << __FUNCTION__ << "()"
928 << " download = " << download->DebugString(true);
929
930 download->Cancel(true);
931 }
932
933 // Operations posted to us from the history service ---------------------------- 872 // Operations posted to us from the history service ----------------------------
934 873
935 // The history service has retrieved all download entries. 'entries' contains 874 // The history service has retrieved all download entries. 'entries' contains
936 // 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time). 875 // 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time).
937 void DownloadManagerImpl::OnPersistentStoreQueryComplete( 876 void DownloadManagerImpl::OnPersistentStoreQueryComplete(
938 std::vector<DownloadPersistentStoreInfo>* entries) { 877 std::vector<DownloadPersistentStoreInfo>* entries) {
939 history_size_ = entries->size(); 878 history_size_ = entries->size();
940 for (size_t i = 0; i < entries->size(); ++i) { 879 for (size_t i = 0; i < entries->size(); ++i) {
941 int64 db_handle = entries->at(i).db_handle; 880 int64 db_handle = entries->at(i).db_handle;
942 base::debug::Alias(&db_handle); 881 base::debug::Alias(&db_handle);
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
1042 int count = 0; 981 int count = 0;
1043 for (DownloadMap::const_iterator it = active_downloads_.begin(); 982 for (DownloadMap::const_iterator it = active_downloads_.begin();
1044 it != active_downloads_.end(); ++it) { 983 it != active_downloads_.end(); ++it) {
1045 DownloadItemImpl* item = it->second; 984 DownloadItemImpl* item = it->second;
1046 if (item->IsInProgress()) 985 if (item->IsInProgress())
1047 ++count; 986 ++count;
1048 } 987 }
1049 return count; 988 return count;
1050 } 989 }
1051 990
1052 // Clears the last download path, used to initialize "save as" dialogs.
1053 void DownloadManagerImpl::ClearLastDownloadPath() {
1054 last_download_path_ = FilePath();
1055 }
1056
1057 void DownloadManagerImpl::NotifyModelChanged() { 991 void DownloadManagerImpl::NotifyModelChanged() {
1058 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged(this)); 992 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged(this));
1059 } 993 }
1060 994
1061 DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) { 995 DownloadItem* DownloadManagerImpl::GetDownloadItem(int download_id) {
1062 DownloadItem* download = GetDownload(download_id); 996 DownloadItem* download = GetDownload(download_id);
1063 return (download && download->IsPersisted()) ? download : NULL; 997 return (download && download->IsPersisted()) ? download : NULL;
1064 } 998 }
1065 999
1066 DownloadItem* DownloadManagerImpl::GetDownload(int download_id) { 1000 DownloadItem* DownloadManagerImpl::GetDownload(int download_id) {
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
1153 if (item->IsComplete() && 1087 if (item->IsComplete() &&
1154 !item->GetOpened()) 1088 !item->GetOpened())
1155 ++num_unopened; 1089 ++num_unopened;
1156 } 1090 }
1157 download_stats::RecordOpensOutstanding(num_unopened); 1091 download_stats::RecordOpensOutstanding(num_unopened);
1158 } 1092 }
1159 1093
1160 void DownloadManagerImpl::DownloadRenamedToIntermediateName( 1094 void DownloadManagerImpl::DownloadRenamedToIntermediateName(
1161 DownloadItemImpl* download) { 1095 DownloadItemImpl* download) {
1162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1096 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1163 // If the rename failed, we receive an OnDownloadInterrupted() call before we 1097 // download->GetFullPath() is only expected to be meaningful after this
1164 // receive the DownloadRenamedToIntermediateName() call. 1098 // callback is received. Therefore we can now add the download to a persistent
1165 if (delegate_) 1099 // store. If the rename failed, we receive an OnDownloadInterrupted() call
1100 // before we receive the DownloadRenamedToIntermediateName() call.
1101 if (delegate_) {
1166 delegate_->AddItemToPersistentStore(download); 1102 delegate_->AddItemToPersistentStore(download);
1103 } else {
1104 OnItemAddedToPersistentStore(download->GetId(),
1105 DownloadItem::kUninitializedHandle);
1106 }
1167 } 1107 }
1168 1108
1169 void DownloadManagerImpl::DownloadRenamedToFinalName( 1109 void DownloadManagerImpl::DownloadRenamedToFinalName(
1170 DownloadItemImpl* download) { 1110 DownloadItemImpl* download) {
1171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1172 // If the rename failed, we receive an OnDownloadInterrupted() call before we 1112 // If the rename failed, we receive an OnDownloadInterrupted() call before we
1173 // receive the DownloadRenamedToFinalName() call. 1113 // receive the DownloadRenamedToFinalName() call.
1174 if (delegate_) { 1114 if (delegate_) {
1175 delegate_->UpdatePathForItemInPersistentStore( 1115 delegate_->UpdatePathForItemInPersistentStore(
1176 download, download->GetFullPath()); 1116 download, download->GetFullPath());
1177 } 1117 }
1178 } 1118 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698