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

Side by Side Diff: chrome/browser/download/download_manager.cc

Issue 6096003: Put history insertion for downloads processing inline. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Incorporated latest round of comments. Created 9 years, 11 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) 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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698