Home | History | Annotate | Download | only in download
      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
      3 // found in the LICENSE file.
      4 
      5 // File method ordering: Methods in this file are in the same order as
      6 // in download_item_impl.h, with the following exception: The public
      7 // interface Start is placed in chronological order with the other
      8 // (private) routines that together define a DownloadItem's state
      9 // transitions as the download progresses.  See "Download progression
     10 // cascade" later in this file.
     11 
     12 // A regular DownloadItem (created for a download in this session of the
     13 // browser) normally goes through the following states:
     14 //      * Created (when download starts)
     15 //      * Destination filename determined
     16 //      * Entered into the history database.
     17 //      * Made visible in the download shelf.
     18 //      * All the data is saved.  Note that the actual data download occurs
     19 //        in parallel with the above steps, but until those steps are
     20 //        complete, the state of the data save will be ignored.
     21 //      * Download file is renamed to its final name, and possibly
     22 //        auto-opened.
     23 
     24 #include "content/browser/download/download_item_impl.h"
     25 
     26 #include <vector>
     27 
     28 #include "base/basictypes.h"
     29 #include "base/bind.h"
     30 #include "base/command_line.h"
     31 #include "base/file_util.h"
     32 #include "base/format_macros.h"
     33 #include "base/logging.h"
     34 #include "base/metrics/histogram.h"
     35 #include "base/stl_util.h"
     36 #include "base/strings/stringprintf.h"
     37 #include "base/strings/utf_string_conversions.h"
     38 #include "content/browser/download/download_create_info.h"
     39 #include "content/browser/download/download_file.h"
     40 #include "content/browser/download/download_interrupt_reasons_impl.h"
     41 #include "content/browser/download/download_item_impl_delegate.h"
     42 #include "content/browser/download/download_request_handle.h"
     43 #include "content/browser/download/download_stats.h"
     44 #include "content/browser/renderer_host/render_view_host_impl.h"
     45 #include "content/browser/web_contents/web_contents_impl.h"
     46 #include "content/public/browser/browser_context.h"
     47 #include "content/public/browser/browser_thread.h"
     48 #include "content/public/browser/content_browser_client.h"
     49 #include "content/public/browser/download_danger_type.h"
     50 #include "content/public/browser/download_interrupt_reasons.h"
     51 #include "content/public/browser/download_url_parameters.h"
     52 #include "content/public/common/content_switches.h"
     53 #include "content/public/common/referrer.h"
     54 #include "net/base/net_util.h"
     55 
     56 namespace content {
     57 
     58 namespace {
     59 
     60 void DeleteDownloadedFile(const base::FilePath& path) {
     61   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     62 
     63   // Make sure we only delete files.
     64   if (!base::DirectoryExists(path))
     65     base::DeleteFile(path, false);
     66 }
     67 
     68 // Wrapper around DownloadFile::Detach and DownloadFile::Cancel that
     69 // takes ownership of the DownloadFile and hence implicitly destroys it
     70 // at the end of the function.
     71 static base::FilePath DownloadFileDetach(
     72     scoped_ptr<DownloadFile> download_file) {
     73   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     74   base::FilePath full_path = download_file->FullPath();
     75   download_file->Detach();
     76   return full_path;
     77 }
     78 
     79 static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) {
     80   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     81   download_file->Cancel();
     82 }
     83 
     84 bool IsDownloadResumptionEnabled() {
     85   return CommandLine::ForCurrentProcess()->HasSwitch(
     86       switches::kEnableDownloadResumption);
     87 }
     88 
     89 }  // namespace
     90 
     91 const uint32 DownloadItem::kInvalidId = 0;
     92 
     93 const char DownloadItem::kEmptyFileHash[] = "";
     94 
     95 // The maximum number of attempts we will make to resume automatically.
     96 const int DownloadItemImpl::kMaxAutoResumeAttempts = 5;
     97 
     98 // Constructor for reading from the history service.
     99 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
    100                                    uint32 download_id,
    101                                    const base::FilePath& current_path,
    102                                    const base::FilePath& target_path,
    103                                    const std::vector<GURL>& url_chain,
    104                                    const GURL& referrer_url,
    105                                    const base::Time& start_time,
    106                                    const base::Time& end_time,
    107                                    const std::string& etag,
    108                                    const std::string& last_modified,
    109                                    int64 received_bytes,
    110                                    int64 total_bytes,
    111                                    DownloadItem::DownloadState state,
    112                                    DownloadDangerType danger_type,
    113                                    DownloadInterruptReason interrupt_reason,
    114                                    bool opened,
    115                                    const net::BoundNetLog& bound_net_log)
    116     : is_save_package_download_(false),
    117       download_id_(download_id),
    118       current_path_(current_path),
    119       target_path_(target_path),
    120       target_disposition_(TARGET_DISPOSITION_OVERWRITE),
    121       url_chain_(url_chain),
    122       referrer_url_(referrer_url),
    123       transition_type_(PAGE_TRANSITION_LINK),
    124       has_user_gesture_(false),
    125       total_bytes_(total_bytes),
    126       received_bytes_(received_bytes),
    127       bytes_per_sec_(0),
    128       last_modified_time_(last_modified),
    129       etag_(etag),
    130       last_reason_(interrupt_reason),
    131       start_tick_(base::TimeTicks()),
    132       state_(ExternalToInternalState(state)),
    133       danger_type_(danger_type),
    134       start_time_(start_time),
    135       end_time_(end_time),
    136       delegate_(delegate),
    137       is_paused_(false),
    138       auto_resume_count_(0),
    139       open_when_complete_(false),
    140       file_externally_removed_(false),
    141       auto_opened_(false),
    142       is_temporary_(false),
    143       all_data_saved_(state == COMPLETE),
    144       destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
    145       opened_(opened),
    146       delegate_delayed_complete_(false),
    147       bound_net_log_(bound_net_log),
    148       weak_ptr_factory_(this) {
    149   delegate_->Attach();
    150   DCHECK_NE(IN_PROGRESS_INTERNAL, state_);
    151   Init(false /* not actively downloading */, SRC_HISTORY_IMPORT);
    152 }
    153 
    154 // Constructing for a regular download:
    155 DownloadItemImpl::DownloadItemImpl(
    156     DownloadItemImplDelegate* delegate,
    157     uint32 download_id,
    158     const DownloadCreateInfo& info,
    159     const net::BoundNetLog& bound_net_log)
    160     : is_save_package_download_(false),
    161       download_id_(download_id),
    162       target_disposition_(
    163           (info.save_info->prompt_for_save_location) ?
    164               TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE),
    165       url_chain_(info.url_chain),
    166       referrer_url_(info.referrer_url),
    167       suggested_filename_(UTF16ToUTF8(info.save_info->suggested_name)),
    168       forced_file_path_(info.save_info->file_path),
    169       transition_type_(info.transition_type),
    170       has_user_gesture_(info.has_user_gesture),
    171       content_disposition_(info.content_disposition),
    172       mime_type_(info.mime_type),
    173       original_mime_type_(info.original_mime_type),
    174       remote_address_(info.remote_address),
    175       total_bytes_(info.total_bytes),
    176       received_bytes_(0),
    177       bytes_per_sec_(0),
    178       last_modified_time_(info.last_modified),
    179       etag_(info.etag),
    180       last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
    181       start_tick_(base::TimeTicks::Now()),
    182       state_(IN_PROGRESS_INTERNAL),
    183       danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
    184       start_time_(info.start_time),
    185       delegate_(delegate),
    186       is_paused_(false),
    187       auto_resume_count_(0),
    188       open_when_complete_(false),
    189       file_externally_removed_(false),
    190       auto_opened_(false),
    191       is_temporary_(!info.save_info->file_path.empty()),
    192       all_data_saved_(false),
    193       destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
    194       opened_(false),
    195       delegate_delayed_complete_(false),
    196       bound_net_log_(bound_net_log),
    197       weak_ptr_factory_(this) {
    198   delegate_->Attach();
    199   Init(true /* actively downloading */, SRC_ACTIVE_DOWNLOAD);
    200 
    201   // Link the event sources.
    202   bound_net_log_.AddEvent(
    203       net::NetLog::TYPE_DOWNLOAD_URL_REQUEST,
    204       info.request_bound_net_log.source().ToEventParametersCallback());
    205 
    206   info.request_bound_net_log.AddEvent(
    207       net::NetLog::TYPE_DOWNLOAD_STARTED,
    208       bound_net_log_.source().ToEventParametersCallback());
    209 }
    210 
    211 // Constructing for the "Save Page As..." feature:
    212 DownloadItemImpl::DownloadItemImpl(
    213     DownloadItemImplDelegate* delegate,
    214     uint32 download_id,
    215     const base::FilePath& path,
    216     const GURL& url,
    217     const std::string& mime_type,
    218     scoped_ptr<DownloadRequestHandleInterface> request_handle,
    219     const net::BoundNetLog& bound_net_log)
    220     : is_save_package_download_(true),
    221       request_handle_(request_handle.Pass()),
    222       download_id_(download_id),
    223       current_path_(path),
    224       target_path_(path),
    225       target_disposition_(TARGET_DISPOSITION_OVERWRITE),
    226       url_chain_(1, url),
    227       referrer_url_(GURL()),
    228       transition_type_(PAGE_TRANSITION_LINK),
    229       has_user_gesture_(false),
    230       mime_type_(mime_type),
    231       original_mime_type_(mime_type),
    232       total_bytes_(0),
    233       received_bytes_(0),
    234       bytes_per_sec_(0),
    235       last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
    236       start_tick_(base::TimeTicks::Now()),
    237       state_(IN_PROGRESS_INTERNAL),
    238       danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
    239       start_time_(base::Time::Now()),
    240       delegate_(delegate),
    241       is_paused_(false),
    242       auto_resume_count_(0),
    243       open_when_complete_(false),
    244       file_externally_removed_(false),
    245       auto_opened_(false),
    246       is_temporary_(false),
    247       all_data_saved_(false),
    248       destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
    249       opened_(false),
    250       delegate_delayed_complete_(false),
    251       bound_net_log_(bound_net_log),
    252       weak_ptr_factory_(this) {
    253   delegate_->Attach();
    254   Init(true /* actively downloading */, SRC_SAVE_PAGE_AS);
    255 }
    256 
    257 DownloadItemImpl::~DownloadItemImpl() {
    258   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    259 
    260   // Should always have been nuked before now, at worst in
    261   // DownloadManager shutdown.
    262   DCHECK(!download_file_.get());
    263 
    264   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this));
    265   delegate_->AssertStateConsistent(this);
    266   delegate_->Detach();
    267 }
    268 
    269 void DownloadItemImpl::AddObserver(Observer* observer) {
    270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    271 
    272   observers_.AddObserver(observer);
    273 }
    274 
    275 void DownloadItemImpl::RemoveObserver(Observer* observer) {
    276   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    277 
    278   observers_.RemoveObserver(observer);
    279 }
    280 
    281 void DownloadItemImpl::UpdateObservers() {
    282   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    283 
    284   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
    285 }
    286 
    287 void DownloadItemImpl::ValidateDangerousDownload() {
    288   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    289   DCHECK(!IsDone());
    290   DCHECK(IsDangerous());
    291 
    292   VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
    293 
    294   if (IsDone() || !IsDangerous())
    295     return;
    296 
    297   RecordDangerousDownloadAccept(GetDangerType());
    298 
    299   danger_type_ = DOWNLOAD_DANGER_TYPE_USER_VALIDATED;
    300 
    301   bound_net_log_.AddEvent(
    302       net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
    303       base::Bind(&ItemCheckedNetLogCallback, GetDangerType()));
    304 
    305   UpdateObservers();
    306 
    307   MaybeCompleteDownload();
    308 }
    309 
    310 void DownloadItemImpl::StealDangerousDownload(
    311     const AcquireFileCallback& callback) {
    312   VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
    313   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    314   DCHECK(IsDangerous());
    315   if (download_file_) {
    316     BrowserThread::PostTaskAndReplyWithResult(
    317         BrowserThread::FILE,
    318         FROM_HERE,
    319         base::Bind(&DownloadFileDetach, base::Passed(&download_file_)),
    320         callback);
    321   } else {
    322     callback.Run(current_path_);
    323   }
    324   current_path_.clear();
    325   Remove();
    326   // We have now been deleted.
    327 }
    328 
    329 void DownloadItemImpl::Pause() {
    330   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    331 
    332   // Ignore irrelevant states.
    333   if (state_ != IN_PROGRESS_INTERNAL || is_paused_)
    334     return;
    335 
    336   request_handle_->PauseRequest();
    337   is_paused_ = true;
    338   UpdateObservers();
    339 }
    340 
    341 void DownloadItemImpl::Resume() {
    342   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    343   switch (state_) {
    344     case IN_PROGRESS_INTERNAL:
    345       if (!is_paused_)
    346         return;
    347       request_handle_->ResumeRequest();
    348       is_paused_ = false;
    349       UpdateObservers();
    350       return;
    351 
    352     case COMPLETING_INTERNAL:
    353     case COMPLETE_INTERNAL:
    354     case CANCELLED_INTERNAL:
    355     case RESUMING_INTERNAL:
    356       return;
    357 
    358     case INTERRUPTED_INTERNAL:
    359       auto_resume_count_ = 0;  // User input resets the counter.
    360       ResumeInterruptedDownload();
    361       return;
    362 
    363     case MAX_DOWNLOAD_INTERNAL_STATE:
    364       NOTREACHED();
    365   }
    366 }
    367 
    368 void DownloadItemImpl::Cancel(bool user_cancel) {
    369   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    370 
    371   VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
    372   if (state_ != IN_PROGRESS_INTERNAL &&
    373       state_ != INTERRUPTED_INTERNAL &&
    374       state_ != RESUMING_INTERNAL) {
    375     // Small downloads might be complete before this method has a chance to run.
    376     return;
    377   }
    378 
    379   if (IsDangerous()) {
    380     RecordDangerousDownloadDiscard(
    381         user_cancel ? DOWNLOAD_DISCARD_DUE_TO_USER_ACTION
    382                     : DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN,
    383         GetDangerType());
    384   }
    385 
    386   last_reason_ = user_cancel ? DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
    387                              : DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
    388 
    389   RecordDownloadCount(CANCELLED_COUNT);
    390 
    391   // TODO(rdsmith/benjhayden): Remove condition as part of
    392   // |SavePackage| integration.
    393   // |download_file_| can be NULL if Interrupt() is called after the
    394   // download file has been released.
    395   if (!is_save_package_download_ && download_file_)
    396     ReleaseDownloadFile(true);
    397 
    398   if (state_ == IN_PROGRESS_INTERNAL) {
    399     // Cancel the originating URL request unless it's already been cancelled
    400     // by interrupt.
    401     request_handle_->CancelRequest();
    402   }
    403 
    404   // Remove the intermediate file if we are cancelling an interrupted download.
    405   // Continuable interruptions leave the intermediate file around.
    406   if ((state_ == INTERRUPTED_INTERNAL || state_ == RESUMING_INTERNAL) &&
    407       !current_path_.empty()) {
    408     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
    409                             base::Bind(&DeleteDownloadedFile, current_path_));
    410     current_path_.clear();
    411   }
    412 
    413   TransitionTo(CANCELLED_INTERNAL, UPDATE_OBSERVERS);
    414 }
    415 
    416 void DownloadItemImpl::Remove() {
    417   VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
    418   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    419 
    420   delegate_->AssertStateConsistent(this);
    421   Cancel(true);
    422   delegate_->AssertStateConsistent(this);
    423 
    424   NotifyRemoved();
    425   delegate_->DownloadRemoved(this);
    426   // We have now been deleted.
    427 }
    428 
    429 void DownloadItemImpl::OpenDownload() {
    430   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    431 
    432   if (!IsDone()) {
    433     // We don't honor the open_when_complete_ flag for temporary
    434     // downloads. Don't set it because it shows up in the UI.
    435     if (!IsTemporary())
    436       open_when_complete_ = !open_when_complete_;
    437     return;
    438   }
    439 
    440   if (state_ != COMPLETE_INTERNAL || file_externally_removed_)
    441     return;
    442 
    443   // Ideally, we want to detect errors in opening and report them, but we
    444   // don't generally have the proper interface for that to the external
    445   // program that opens the file.  So instead we spawn a check to update
    446   // the UI if the file has been deleted in parallel with the open.
    447   delegate_->CheckForFileRemoval(this);
    448   RecordOpen(GetEndTime(), !GetOpened());
    449   opened_ = true;
    450   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this));
    451   delegate_->OpenDownload(this);
    452 }
    453 
    454 void DownloadItemImpl::ShowDownloadInShell() {
    455   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    456 
    457   delegate_->ShowDownloadInShell(this);
    458 }
    459 
    460 uint32 DownloadItemImpl::GetId() const {
    461   return download_id_;
    462 }
    463 
    464 DownloadItem::DownloadState DownloadItemImpl::GetState() const {
    465   return InternalToExternalState(state_);
    466 }
    467 
    468 DownloadInterruptReason DownloadItemImpl::GetLastReason() const {
    469   return last_reason_;
    470 }
    471 
    472 bool DownloadItemImpl::IsPaused() const {
    473   return is_paused_;
    474 }
    475 
    476 bool DownloadItemImpl::IsTemporary() const {
    477   return is_temporary_;
    478 }
    479 
    480 bool DownloadItemImpl::CanResume() const {
    481   if ((GetState() == IN_PROGRESS) && IsPaused())
    482     return true;
    483 
    484   if (state_ != INTERRUPTED_INTERNAL)
    485     return false;
    486 
    487   // Downloads that don't have a WebContents should still be resumable, but this
    488   // isn't currently the case. See ResumeInterruptedDownload().
    489   if (!GetWebContents())
    490     return false;
    491 
    492   ResumeMode resume_mode = GetResumeMode();
    493   return IsDownloadResumptionEnabled() &&
    494       (resume_mode == RESUME_MODE_USER_RESTART ||
    495        resume_mode == RESUME_MODE_USER_CONTINUE);
    496 }
    497 
    498 bool DownloadItemImpl::IsDone() const {
    499   switch (state_) {
    500     case IN_PROGRESS_INTERNAL:
    501     case COMPLETING_INTERNAL:
    502       return false;
    503 
    504     case COMPLETE_INTERNAL:
    505     case CANCELLED_INTERNAL:
    506       return true;
    507 
    508     case INTERRUPTED_INTERNAL:
    509       return !CanResume();
    510 
    511     case RESUMING_INTERNAL:
    512       return false;
    513 
    514     case MAX_DOWNLOAD_INTERNAL_STATE:
    515       break;
    516   }
    517   NOTREACHED();
    518   return true;
    519 }
    520 
    521 const GURL& DownloadItemImpl::GetURL() const {
    522   return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.back();
    523 }
    524 
    525 const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const {
    526   return url_chain_;
    527 }
    528 
    529 const GURL& DownloadItemImpl::GetOriginalUrl() const {
    530   // Be careful about taking the front() of possibly-empty vectors!
    531   // http://crbug.com/190096
    532   return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.front();
    533 }
    534 
    535 const GURL& DownloadItemImpl::GetReferrerUrl() const {
    536   return referrer_url_;
    537 }
    538 
    539 std::string DownloadItemImpl::GetSuggestedFilename() const {
    540   return suggested_filename_;
    541 }
    542 
    543 std::string DownloadItemImpl::GetContentDisposition() const {
    544   return content_disposition_;
    545 }
    546 
    547 std::string DownloadItemImpl::GetMimeType() const {
    548   return mime_type_;
    549 }
    550 
    551 std::string DownloadItemImpl::GetOriginalMimeType() const {
    552   return original_mime_type_;
    553 }
    554 
    555 std::string DownloadItemImpl::GetRemoteAddress() const {
    556   return remote_address_;
    557 }
    558 
    559 bool DownloadItemImpl::HasUserGesture() const {
    560   return has_user_gesture_;
    561 };
    562 
    563 PageTransition DownloadItemImpl::GetTransitionType() const {
    564   return transition_type_;
    565 };
    566 
    567 const std::string& DownloadItemImpl::GetLastModifiedTime() const {
    568   return last_modified_time_;
    569 }
    570 
    571 const std::string& DownloadItemImpl::GetETag() const {
    572   return etag_;
    573 }
    574 
    575 bool DownloadItemImpl::IsSavePackageDownload() const {
    576   return is_save_package_download_;
    577 }
    578 
    579 const base::FilePath& DownloadItemImpl::GetFullPath() const {
    580   return current_path_;
    581 }
    582 
    583 const base::FilePath& DownloadItemImpl::GetTargetFilePath() const {
    584   return target_path_;
    585 }
    586 
    587 const base::FilePath& DownloadItemImpl::GetForcedFilePath() const {
    588   // TODO(asanka): Get rid of GetForcedFilePath(). We should instead just
    589   // require that clients respect GetTargetFilePath() if it is already set.
    590   return forced_file_path_;
    591 }
    592 
    593 base::FilePath DownloadItemImpl::GetFileNameToReportUser() const {
    594   if (!display_name_.empty())
    595     return display_name_;
    596   return target_path_.BaseName();
    597 }
    598 
    599 DownloadItem::TargetDisposition DownloadItemImpl::GetTargetDisposition() const {
    600   return target_disposition_;
    601 }
    602 
    603 const std::string& DownloadItemImpl::GetHash() const {
    604   return hash_;
    605 }
    606 
    607 const std::string& DownloadItemImpl::GetHashState() const {
    608   return hash_state_;
    609 }
    610 
    611 bool DownloadItemImpl::GetFileExternallyRemoved() const {
    612   return file_externally_removed_;
    613 }
    614 
    615 void DownloadItemImpl::DeleteFile() {
    616   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    617   if ((GetState() != DownloadItem::COMPLETE) ||
    618       file_externally_removed_) {
    619     return;
    620   }
    621   BrowserThread::PostTaskAndReply(
    622       BrowserThread::FILE, FROM_HERE,
    623       base::Bind(&DeleteDownloadedFile, current_path_),
    624       base::Bind(&DownloadItemImpl::OnDownloadedFileRemoved,
    625                  weak_ptr_factory_.GetWeakPtr()));
    626   current_path_.clear();
    627 }
    628 
    629 bool DownloadItemImpl::IsDangerous() const {
    630 #if defined(OS_WIN)
    631   // TODO(noelutz): At this point only the windows views UI supports
    632   // warnings based on dangerous content.
    633   return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
    634           danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
    635           danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
    636           danger_type_ == DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
    637           danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
    638           danger_type_ == DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
    639 #else
    640   return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
    641           danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL);
    642 #endif
    643 }
    644 
    645 DownloadDangerType DownloadItemImpl::GetDangerType() const {
    646   return danger_type_;
    647 }
    648 
    649 bool DownloadItemImpl::TimeRemaining(base::TimeDelta* remaining) const {
    650   if (total_bytes_ <= 0)
    651     return false;  // We never received the content_length for this download.
    652 
    653   int64 speed = CurrentSpeed();
    654   if (speed == 0)
    655     return false;
    656 
    657   *remaining = base::TimeDelta::FromSeconds(
    658       (total_bytes_ - received_bytes_) / speed);
    659   return true;
    660 }
    661 
    662 int64 DownloadItemImpl::CurrentSpeed() const {
    663   if (is_paused_)
    664     return 0;
    665   return bytes_per_sec_;
    666 }
    667 
    668 int DownloadItemImpl::PercentComplete() const {
    669   // If the delegate is delaying completion of the download, then we have no
    670   // idea how long it will take.
    671   if (delegate_delayed_complete_ || total_bytes_ <= 0)
    672     return -1;
    673 
    674   return static_cast<int>(received_bytes_ * 100.0 / total_bytes_);
    675 }
    676 
    677 bool DownloadItemImpl::AllDataSaved() const {
    678   return all_data_saved_;
    679 }
    680 
    681 int64 DownloadItemImpl::GetTotalBytes() const {
    682   return total_bytes_;
    683 }
    684 
    685 int64 DownloadItemImpl::GetReceivedBytes() const {
    686   return received_bytes_;
    687 }
    688 
    689 base::Time DownloadItemImpl::GetStartTime() const {
    690   return start_time_;
    691 }
    692 
    693 base::Time DownloadItemImpl::GetEndTime() const {
    694   return end_time_;
    695 }
    696 
    697 bool DownloadItemImpl::CanShowInFolder() {
    698   // A download can be shown in the folder if the downloaded file is in a known
    699   // location.
    700   return CanOpenDownload() && !GetFullPath().empty();
    701 }
    702 
    703 bool DownloadItemImpl::CanOpenDownload() {
    704   // We can open the file or mark it for opening on completion if the download
    705   // is expected to complete successfully. Exclude temporary downloads, since
    706   // they aren't owned by the download system.
    707   const bool is_complete = GetState() == DownloadItem::COMPLETE;
    708   return (!IsDone() || is_complete) && !IsTemporary() &&
    709          !file_externally_removed_;
    710 }
    711 
    712 bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() {
    713   return delegate_->ShouldOpenFileBasedOnExtension(GetTargetFilePath());
    714 }
    715 
    716 bool DownloadItemImpl::GetOpenWhenComplete() const {
    717   return open_when_complete_;
    718 }
    719 
    720 bool DownloadItemImpl::GetAutoOpened() {
    721   return auto_opened_;
    722 }
    723 
    724 bool DownloadItemImpl::GetOpened() const {
    725   return opened_;
    726 }
    727 
    728 BrowserContext* DownloadItemImpl::GetBrowserContext() const {
    729   return delegate_->GetBrowserContext();
    730 }
    731 
    732 WebContents* DownloadItemImpl::GetWebContents() const {
    733   // TODO(rdsmith): Remove null check after removing GetWebContents() from
    734   // paths that might be used by DownloadItems created from history import.
    735   // Currently such items have null request_handle_s, where other items
    736   // (regular and SavePackage downloads) have actual objects off the pointer.
    737   if (request_handle_)
    738     return request_handle_->GetWebContents();
    739   return NULL;
    740 }
    741 
    742 void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type) {
    743   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    744   DCHECK(AllDataSaved());
    745   VLOG(20) << __FUNCTION__ << " danger_type=" << danger_type
    746            << " download=" << DebugString(true);
    747   SetDangerType(danger_type);
    748   UpdateObservers();
    749 }
    750 
    751 void DownloadItemImpl::SetOpenWhenComplete(bool open) {
    752   open_when_complete_ = open;
    753 }
    754 
    755 void DownloadItemImpl::SetIsTemporary(bool temporary) {
    756   is_temporary_ = temporary;
    757 }
    758 
    759 void DownloadItemImpl::SetOpened(bool opened) {
    760   opened_ = opened;
    761 }
    762 
    763 void DownloadItemImpl::SetDisplayName(const base::FilePath& name) {
    764   display_name_ = name;
    765 }
    766 
    767 std::string DownloadItemImpl::DebugString(bool verbose) const {
    768   std::string description =
    769       base::StringPrintf("{ id = %d"
    770                          " state = %s",
    771                          download_id_,
    772                          DebugDownloadStateString(state_));
    773 
    774   // Construct a string of the URL chain.
    775   std::string url_list("<none>");
    776   if (!url_chain_.empty()) {
    777     std::vector<GURL>::const_iterator iter = url_chain_.begin();
    778     std::vector<GURL>::const_iterator last = url_chain_.end();
    779     url_list = (*iter).is_valid() ? (*iter).spec() : "<invalid>";
    780     ++iter;
    781     for ( ; verbose && (iter != last); ++iter) {
    782       url_list += " ->\n\t";
    783       const GURL& next_url = *iter;
    784       url_list += next_url.is_valid() ? next_url.spec() : "<invalid>";
    785     }
    786   }
    787 
    788   if (verbose) {
    789     description += base::StringPrintf(
    790         " total = %" PRId64
    791         " received = %" PRId64
    792         " reason = %s"
    793         " paused = %c"
    794         " resume_mode = %s"
    795         " auto_resume_count = %d"
    796         " danger = %d"
    797         " all_data_saved = %c"
    798         " last_modified = '%s'"
    799         " etag = '%s'"
    800         " has_download_file = %s"
    801         " url_chain = \n\t\"%s\"\n\t"
    802         " full_path = \"%" PRFilePath "\"\n\t"
    803         " target_path = \"%" PRFilePath "\"",
    804         GetTotalBytes(),
    805         GetReceivedBytes(),
    806         InterruptReasonDebugString(last_reason_).c_str(),
    807         IsPaused() ? 'T' : 'F',
    808         DebugResumeModeString(GetResumeMode()),
    809         auto_resume_count_,
    810         GetDangerType(),
    811         AllDataSaved() ? 'T' : 'F',
    812         GetLastModifiedTime().c_str(),
    813         GetETag().c_str(),
    814         download_file_.get() ? "true" : "false",
    815         url_list.c_str(),
    816         GetFullPath().value().c_str(),
    817         GetTargetFilePath().value().c_str());
    818   } else {
    819     description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
    820   }
    821 
    822   description += " }";
    823 
    824   return description;
    825 }
    826 
    827 DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
    828   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    829   // We can't continue without a handle on the intermediate file.
    830   // We also can't continue if we don't have some verifier to make sure
    831   // we're getting the same file.
    832   const bool force_restart =
    833       (current_path_.empty() || (etag_.empty() && last_modified_time_.empty()));
    834 
    835   // We won't auto-restart if we've used up our attempts or the
    836   // download has been paused by user action.
    837   const bool force_user =
    838       (auto_resume_count_ >= kMaxAutoResumeAttempts || is_paused_);
    839 
    840   ResumeMode mode = RESUME_MODE_INVALID;
    841 
    842   switch(last_reason_) {
    843     case DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
    844     case DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
    845       if (force_restart && force_user)
    846         mode = RESUME_MODE_USER_RESTART;
    847       else if (force_restart)
    848         mode = RESUME_MODE_IMMEDIATE_RESTART;
    849       else if (force_user)
    850         mode = RESUME_MODE_USER_CONTINUE;
    851       else
    852         mode = RESUME_MODE_IMMEDIATE_CONTINUE;
    853       break;
    854 
    855     case DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION:
    856     case DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
    857     case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
    858       if (force_user)
    859         mode = RESUME_MODE_USER_RESTART;
    860       else
    861         mode = RESUME_MODE_IMMEDIATE_RESTART;
    862       break;
    863 
    864     case DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
    865     case DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
    866     case DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
    867     case DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
    868     case DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
    869     case DOWNLOAD_INTERRUPT_REASON_CRASH:
    870       if (force_restart)
    871         mode = RESUME_MODE_USER_RESTART;
    872       else
    873         mode = RESUME_MODE_USER_CONTINUE;
    874       break;
    875 
    876     case DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
    877     case DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
    878     case DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
    879     case DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
    880     case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
    881       mode = RESUME_MODE_USER_RESTART;
    882       break;
    883 
    884     case DOWNLOAD_INTERRUPT_REASON_NONE:
    885     case DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
    886     case DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
    887     case DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
    888     case DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
    889     case DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
    890       mode = RESUME_MODE_INVALID;
    891       break;
    892   }
    893 
    894   return mode;
    895 }
    896 
    897 void DownloadItemImpl::NotifyRemoved() {
    898   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this));
    899 }
    900 
    901 void DownloadItemImpl::OnDownloadedFileRemoved() {
    902   file_externally_removed_ = true;
    903   VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
    904   UpdateObservers();
    905 }
    906 
    907 base::WeakPtr<DownloadDestinationObserver>
    908 DownloadItemImpl::DestinationObserverAsWeakPtr() {
    909   return weak_ptr_factory_.GetWeakPtr();
    910 }
    911 
    912 const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
    913   return bound_net_log_;
    914 }
    915 
    916 void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
    917   total_bytes_ = total_bytes;
    918 }
    919 
    920 void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
    921   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    922 
    923   DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
    924   DCHECK(!all_data_saved_);
    925   all_data_saved_ = true;
    926   VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
    927 
    928   // Store final hash and null out intermediate serialized hash state.
    929   hash_ = final_hash;
    930   hash_state_ = "";
    931 
    932   UpdateObservers();
    933 }
    934 
    935 void DownloadItemImpl::MarkAsComplete() {
    936   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    937 
    938   DCHECK(all_data_saved_);
    939   end_time_ = base::Time::Now();
    940   TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS);
    941 }
    942 
    943 void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far,
    944                                          int64 bytes_per_sec,
    945                                          const std::string& hash_state) {
    946   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    947   VLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far
    948            << " per_sec=" << bytes_per_sec << " download=" << DebugString(true);
    949 
    950   if (GetState() != IN_PROGRESS) {
    951     // Ignore if we're no longer in-progress.  This can happen if we race a
    952     // Cancel on the UI thread with an update on the FILE thread.
    953     //
    954     // TODO(rdsmith): Arguably we should let this go through, as this means
    955     // the download really did get further than we know before it was
    956     // cancelled.  But the gain isn't very large, and the code is more
    957     // fragile if it has to support in progress updates in a non-in-progress
    958     // state.  This issue should be readdressed when we revamp performance
    959     // reporting.
    960     return;
    961   }
    962   bytes_per_sec_ = bytes_per_sec;
    963   hash_state_ = hash_state;
    964   received_bytes_ = bytes_so_far;
    965 
    966   // If we've received more data than we were expecting (bad server info?),
    967   // revert to 'unknown size mode'.
    968   if (received_bytes_ > total_bytes_)
    969     total_bytes_ = 0;
    970 
    971   if (bound_net_log_.IsLoggingAllEvents()) {
    972     bound_net_log_.AddEvent(
    973         net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
    974         net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
    975   }
    976 
    977   UpdateObservers();
    978 }
    979 
    980 void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) {
    981   // Postpone recognition of this error until after file name determination
    982   // has completed and the intermediate file has been renamed to simplify
    983   // resumption conditions.
    984   if (current_path_.empty() || target_path_.empty())
    985     destination_error_ = reason;
    986   else
    987     Interrupt(reason);
    988 }
    989 
    990 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
    991   VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
    992   if (GetState() != IN_PROGRESS)
    993     return;
    994   OnAllDataSaved(final_hash);
    995   MaybeCompleteDownload();
    996 }
    997 
    998 // **** Download progression cascade
    999 
   1000 void DownloadItemImpl::Init(bool active,
   1001                             DownloadType download_type) {
   1002   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1003 
   1004   if (active)
   1005     RecordDownloadCount(START_COUNT);
   1006 
   1007   std::string file_name;
   1008   if (download_type == SRC_HISTORY_IMPORT) {
   1009     // target_path_ works for History and Save As versions.
   1010     file_name = target_path_.AsUTF8Unsafe();
   1011   } else {
   1012     // See if it's set programmatically.
   1013     file_name = forced_file_path_.AsUTF8Unsafe();
   1014     // Possibly has a 'download' attribute for the anchor.
   1015     if (file_name.empty())
   1016       file_name = suggested_filename_;
   1017     // From the URL file name.
   1018     if (file_name.empty())
   1019       file_name = GetURL().ExtractFileName();
   1020   }
   1021 
   1022   base::Callback<base::Value*(net::NetLog::LogLevel)> active_data = base::Bind(
   1023       &ItemActivatedNetLogCallback, this, download_type, &file_name);
   1024   if (active) {
   1025     bound_net_log_.BeginEvent(
   1026         net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
   1027   } else {
   1028     bound_net_log_.AddEvent(
   1029         net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
   1030   }
   1031 
   1032   VLOG(20) << __FUNCTION__ << "() " << DebugString(true);
   1033 }
   1034 
   1035 // We're starting the download.
   1036 void DownloadItemImpl::Start(
   1037     scoped_ptr<DownloadFile> file,
   1038     scoped_ptr<DownloadRequestHandleInterface> req_handle) {
   1039   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1040   DCHECK(!download_file_.get());
   1041   DCHECK(file.get());
   1042   DCHECK(req_handle.get());
   1043 
   1044   download_file_ = file.Pass();
   1045   request_handle_ = req_handle.Pass();
   1046 
   1047   if (GetState() == CANCELLED) {
   1048     // The download was in the process of resuming when it was cancelled. Don't
   1049     // proceed.
   1050     ReleaseDownloadFile(true);
   1051     request_handle_->CancelRequest();
   1052     return;
   1053   }
   1054 
   1055   TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS);
   1056 
   1057   BrowserThread::PostTask(
   1058       BrowserThread::FILE, FROM_HERE,
   1059       base::Bind(&DownloadFile::Initialize,
   1060                  // Safe because we control download file lifetime.
   1061                  base::Unretained(download_file_.get()),
   1062                  base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
   1063                             weak_ptr_factory_.GetWeakPtr())));
   1064 }
   1065 
   1066 void DownloadItemImpl::OnDownloadFileInitialized(
   1067     DownloadInterruptReason result) {
   1068   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1069   if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
   1070     Interrupt(result);
   1071     // TODO(rdsmith/asanka): Arguably we should show this in the UI, but
   1072     // it's not at all clear what to show--we haven't done filename
   1073     // determination, so we don't know what name to display.  OTOH,
   1074     // the failure mode of not showing the DI if the file initialization
   1075     // fails isn't a good one.  Can we hack up a name based on the
   1076     // URLRequest?  We'll need to make sure that initialization happens
   1077     // properly.  Possibly the right thing is to have the UI handle
   1078     // this case specially.
   1079     return;
   1080   }
   1081 
   1082   delegate_->DetermineDownloadTarget(
   1083       this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
   1084                        weak_ptr_factory_.GetWeakPtr()));
   1085 }
   1086 
   1087 // Called by delegate_ when the download target path has been
   1088 // determined.
   1089 void DownloadItemImpl::OnDownloadTargetDetermined(
   1090     const base::FilePath& target_path,
   1091     TargetDisposition disposition,
   1092     DownloadDangerType danger_type,
   1093     const base::FilePath& intermediate_path) {
   1094   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1095 
   1096   // If the |target_path| is empty, then we consider this download to be
   1097   // canceled.
   1098   if (target_path.empty()) {
   1099     Cancel(true);
   1100     return;
   1101   }
   1102 
   1103   // TODO(rdsmith,asanka): We are ignoring the possibility that the download
   1104   // has been interrupted at this point until we finish the intermediate
   1105   // rename and set the full path.  That's dangerous, because we might race
   1106   // with resumption, either manual (because the interrupt is visible to the
   1107   // UI) or automatic.  If we keep the "ignore an error on download until file
   1108   // name determination complete" semantics, we need to make sure that the
   1109   // error is kept completely invisible until that point.
   1110 
   1111   VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition
   1112            << " " << danger_type << " " << DebugString(true);
   1113 
   1114   target_path_ = target_path;
   1115   target_disposition_ = disposition;
   1116   SetDangerType(danger_type);
   1117 
   1118   // We want the intermediate and target paths to refer to the same directory so
   1119   // that they are both on the same device and subject to same
   1120   // space/permission/availability constraints.
   1121   DCHECK(intermediate_path.DirName() == target_path.DirName());
   1122 
   1123   // During resumption, we may choose to proceed with the same intermediate
   1124   // file. No rename is necessary if our intermediate file already has the
   1125   // correct name.
   1126   //
   1127   // The intermediate name may change from its original value during filename
   1128   // determination on resumption, for example if the reason for the interruption
   1129   // was the download target running out space, resulting in a user prompt.
   1130   if (intermediate_path == current_path_) {
   1131     OnDownloadRenamedToIntermediateName(DOWNLOAD_INTERRUPT_REASON_NONE,
   1132                                         intermediate_path);
   1133     return;
   1134   }
   1135 
   1136   // Rename to intermediate name.
   1137   // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a
   1138   //               spurious rename when we can just rename to the final
   1139   //               filename. Unnecessary renames may cause bugs like
   1140   //               http://crbug.com/74187.
   1141   DCHECK(!is_save_package_download_);
   1142   DCHECK(download_file_.get());
   1143   DownloadFile::RenameCompletionCallback callback =
   1144       base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName,
   1145                  weak_ptr_factory_.GetWeakPtr());
   1146   BrowserThread::PostTask(
   1147       BrowserThread::FILE, FROM_HERE,
   1148       base::Bind(&DownloadFile::RenameAndUniquify,
   1149                  // Safe because we control download file lifetime.
   1150                  base::Unretained(download_file_.get()),
   1151                  intermediate_path, callback));
   1152 }
   1153 
   1154 void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
   1155     DownloadInterruptReason reason,
   1156     const base::FilePath& full_path) {
   1157   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1158   VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
   1159 
   1160   if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) {
   1161     // Process destination error.  If both |reason| and |destination_error_|
   1162     // refer to actual errors, we want to use the |destination_error_| as the
   1163     // argument to the Interrupt() routine, as it happened first.
   1164     if (reason == DOWNLOAD_INTERRUPT_REASON_NONE)
   1165       SetFullPath(full_path);
   1166     Interrupt(destination_error_);
   1167     destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
   1168   } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
   1169     Interrupt(reason);
   1170     // All file errors result in file deletion above; no need to cleanup.  The
   1171     // current_path_ should be empty. Resuming this download will force a
   1172     // restart and a re-doing of filename determination.
   1173     DCHECK(current_path_.empty());
   1174   } else {
   1175     SetFullPath(full_path);
   1176     UpdateObservers();
   1177     MaybeCompleteDownload();
   1178   }
   1179 }
   1180 
   1181 // When SavePackage downloads MHTML to GData (see
   1182 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
   1183 // does for non-SavePackage downloads, but SavePackage downloads never satisfy
   1184 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
   1185 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage
   1186 // notices that the upload has completed and runs its normal Finish() pathway.
   1187 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes
   1188 // downloads. SavePackage always uses its own Finish() to mark downloads
   1189 // complete.
   1190 void DownloadItemImpl::MaybeCompleteDownload() {
   1191   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1192   DCHECK(!is_save_package_download_);
   1193 
   1194   if (!IsDownloadReadyForCompletion(
   1195           base::Bind(&DownloadItemImpl::MaybeCompleteDownload,
   1196                      weak_ptr_factory_.GetWeakPtr())))
   1197     return;
   1198 
   1199   // TODO(rdsmith): DCHECK that we only pass through this point
   1200   // once per download.  The natural way to do this is by a state
   1201   // transition on the DownloadItem.
   1202 
   1203   // Confirm we're in the proper set of states to be here;
   1204   // have all data, have a history handle, (validated or safe).
   1205   DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
   1206   DCHECK(!IsDangerous());
   1207   DCHECK(all_data_saved_);
   1208 
   1209   OnDownloadCompleting();
   1210 }
   1211 
   1212 // Called by MaybeCompleteDownload() when it has determined that the download
   1213 // is ready for completion.
   1214 void DownloadItemImpl::OnDownloadCompleting() {
   1215   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1216 
   1217   if (state_ != IN_PROGRESS_INTERNAL)
   1218     return;
   1219 
   1220   VLOG(20) << __FUNCTION__ << "()"
   1221            << " " << DebugString(true);
   1222   DCHECK(!GetTargetFilePath().empty());
   1223   DCHECK(!IsDangerous());
   1224 
   1225   // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration.
   1226   if (is_save_package_download_) {
   1227     // Avoid doing anything on the file thread; there's nothing we control
   1228     // there.
   1229     // Strictly speaking, this skips giving the embedder a chance to open
   1230     // the download.  But on a save package download, there's no real
   1231     // concept of opening.
   1232     Completed();
   1233     return;
   1234   }
   1235 
   1236   DCHECK(download_file_.get());
   1237   // Unilaterally rename; even if it already has the right name,
   1238   // we need theannotation.
   1239   DownloadFile::RenameCompletionCallback callback =
   1240       base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName,
   1241                  weak_ptr_factory_.GetWeakPtr());
   1242   BrowserThread::PostTask(
   1243       BrowserThread::FILE, FROM_HERE,
   1244       base::Bind(&DownloadFile::RenameAndAnnotate,
   1245                  base::Unretained(download_file_.get()),
   1246                  GetTargetFilePath(), callback));
   1247 }
   1248 
   1249 void DownloadItemImpl::OnDownloadRenamedToFinalName(
   1250     DownloadInterruptReason reason,
   1251     const base::FilePath& full_path) {
   1252   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1253   DCHECK(!is_save_package_download_);
   1254 
   1255   // If a cancel or interrupt hit, we'll cancel the DownloadFile, which
   1256   // will result in deleting the file on the file thread.  So we don't
   1257   // care about the name having been changed.
   1258   if (state_ != IN_PROGRESS_INTERNAL)
   1259     return;
   1260 
   1261   VLOG(20) << __FUNCTION__ << "()"
   1262            << " full_path = \"" << full_path.value() << "\""
   1263            << " " << DebugString(false);
   1264 
   1265   if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
   1266     Interrupt(reason);
   1267 
   1268     // All file errors should have resulted in in file deletion above. On
   1269     // resumption we will need to re-do filename determination.
   1270     DCHECK(current_path_.empty());
   1271     return;
   1272   }
   1273 
   1274   DCHECK(target_path_ == full_path);
   1275 
   1276   if (full_path != current_path_) {
   1277     // full_path is now the current and target file path.
   1278     DCHECK(!full_path.empty());
   1279     SetFullPath(full_path);
   1280   }
   1281 
   1282   // Complete the download and release the DownloadFile.
   1283   DCHECK(download_file_.get());
   1284   ReleaseDownloadFile(false);
   1285 
   1286   // We're not completely done with the download item yet, but at this
   1287   // point we're committed to complete the download.  Cancels (or Interrupts,
   1288   // though it's not clear how they could happen) after this point will be
   1289   // ignored.
   1290   TransitionTo(COMPLETING_INTERNAL, DONT_UPDATE_OBSERVERS);
   1291 
   1292   if (delegate_->ShouldOpenDownload(
   1293           this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened,
   1294                            weak_ptr_factory_.GetWeakPtr()))) {
   1295     Completed();
   1296   } else {
   1297     delegate_delayed_complete_ = true;
   1298     UpdateObservers();
   1299   }
   1300 }
   1301 
   1302 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
   1303   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1304 
   1305   auto_opened_ = auto_opened;
   1306   Completed();
   1307 }
   1308 
   1309 void DownloadItemImpl::Completed() {
   1310   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1311 
   1312   VLOG(20) << __FUNCTION__ << "() " << DebugString(false);
   1313 
   1314   DCHECK(all_data_saved_);
   1315   end_time_ = base::Time::Now();
   1316   TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS);
   1317   RecordDownloadCompleted(start_tick_, received_bytes_);
   1318 
   1319   if (auto_opened_) {
   1320     // If it was already handled by the delegate, do nothing.
   1321   } else if (GetOpenWhenComplete() ||
   1322              ShouldOpenFileBasedOnExtension() ||
   1323              IsTemporary()) {
   1324     // If the download is temporary, like in drag-and-drop, do not open it but
   1325     // we still need to set it auto-opened so that it can be removed from the
   1326     // download shelf.
   1327     if (!IsTemporary())
   1328       OpenDownload();
   1329 
   1330     auto_opened_ = true;
   1331     UpdateObservers();
   1332   }
   1333 }
   1334 
   1335 void DownloadItemImpl::OnResumeRequestStarted(DownloadItem* item,
   1336                                               net::Error error) {
   1337   // If |item| is not NULL, then Start() has been called already, and nothing
   1338   // more needs to be done here.
   1339   if (item) {
   1340     DCHECK_EQ(net::OK, error);
   1341     DCHECK_EQ(static_cast<DownloadItem*>(this), item);
   1342     return;
   1343   }
   1344   // Otherwise, the request failed without passing through
   1345   // DownloadResourceHandler::OnResponseStarted.
   1346   if (error == net::OK)
   1347     error = net::ERR_FAILED;
   1348   DownloadInterruptReason reason =
   1349       ConvertNetErrorToInterruptReason(error, DOWNLOAD_INTERRUPT_FROM_NETWORK);
   1350   DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason);
   1351   Interrupt(reason);
   1352 }
   1353 
   1354 // **** End of Download progression cascade
   1355 
   1356 // An error occurred somewhere.
   1357 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
   1358   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1359 
   1360   // Somewhat counter-intuitively, it is possible for us to receive an
   1361   // interrupt after we've already been interrupted.  The generation of
   1362   // interrupts from the file thread Renames and the generation of
   1363   // interrupts from disk writes go through two different mechanisms (driven
   1364   // by rename requests from UI thread and by write requests from IO thread,
   1365   // respectively), and since we choose not to keep state on the File thread,
   1366   // this is the place where the races collide.  It's also possible for
   1367   // interrupts to race with cancels.
   1368 
   1369   // Whatever happens, the first one to hit the UI thread wins.
   1370   if (state_ != IN_PROGRESS_INTERNAL && state_ != RESUMING_INTERNAL)
   1371     return;
   1372 
   1373   last_reason_ = reason;
   1374 
   1375   ResumeMode resume_mode = GetResumeMode();
   1376 
   1377   if (state_ == IN_PROGRESS_INTERNAL) {
   1378     // Cancel (delete file) if we're going to restart; no point in leaving
   1379     // data around we aren't going to use.  Also cancel if resumption isn't
   1380     // enabled for the same reason.
   1381     ReleaseDownloadFile(resume_mode == RESUME_MODE_IMMEDIATE_RESTART ||
   1382                         resume_mode == RESUME_MODE_USER_RESTART ||
   1383                         !IsDownloadResumptionEnabled());
   1384 
   1385     // Cancel the originating URL request.
   1386     request_handle_->CancelRequest();
   1387   } else {
   1388     DCHECK(!download_file_.get());
   1389   }
   1390 
   1391   // Reset all data saved, as even if we did save all the data we're going
   1392   // to go through another round of downloading when we resume.
   1393   // There's a potential problem here in the abstract, as if we did download
   1394   // all the data and then run into a continuable error, on resumption we
   1395   // won't download any more data.  However, a) there are currently no
   1396   // continuable errors that can occur after we download all the data, and
   1397   // b) if there were, that would probably simply result in a null range
   1398   // request, which would generate a DestinationCompleted() notification
   1399   // from the DownloadFile, which would behave properly with setting
   1400   // all_data_saved_ to false here.
   1401   all_data_saved_ = false;
   1402 
   1403   TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS);
   1404   RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
   1405   if (!GetWebContents())
   1406     RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
   1407 
   1408   AutoResumeIfValid();
   1409   UpdateObservers();
   1410 }
   1411 
   1412 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) {
   1413   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1414 
   1415   if (destroy_file) {
   1416     BrowserThread::PostTask(
   1417         BrowserThread::FILE, FROM_HERE,
   1418         // Will be deleted at end of task execution.
   1419         base::Bind(&DownloadFileCancel, base::Passed(&download_file_)));
   1420     // Avoid attempting to reuse the intermediate file by clearing out
   1421     // current_path_.
   1422     current_path_.clear();
   1423   } else {
   1424     BrowserThread::PostTask(
   1425         BrowserThread::FILE,
   1426         FROM_HERE,
   1427         base::Bind(base::IgnoreResult(&DownloadFileDetach),
   1428                    // Will be deleted at end of task execution.
   1429                    base::Passed(&download_file_)));
   1430   }
   1431   // Don't accept any more messages from the DownloadFile, and null
   1432   // out any previous "all data received".  This also breaks links to
   1433   // other entities we've given out weak pointers to.
   1434   weak_ptr_factory_.InvalidateWeakPtrs();
   1435 }
   1436 
   1437 bool DownloadItemImpl::IsDownloadReadyForCompletion(
   1438     const base::Closure& state_change_notification) {
   1439   // If we don't have all the data, the download is not ready for
   1440   // completion.
   1441   if (!AllDataSaved())
   1442     return false;
   1443 
   1444   // If the download is dangerous, but not yet validated, it's not ready for
   1445   // completion.
   1446   if (IsDangerous())
   1447     return false;
   1448 
   1449   // If the download isn't active (e.g. has been cancelled) it's not
   1450   // ready for completion.
   1451   if (state_ != IN_PROGRESS_INTERNAL)
   1452     return false;
   1453 
   1454   // If the target filename hasn't been determined, then it's not ready for
   1455   // completion. This is checked in ReadyForDownloadCompletionDone().
   1456   if (GetTargetFilePath().empty())
   1457     return false;
   1458 
   1459   // This is checked in NeedsRename(). Without this conditional,
   1460   // browser_tests:DownloadTest.DownloadMimeType fails the DCHECK.
   1461   if (target_path_.DirName() != current_path_.DirName())
   1462     return false;
   1463 
   1464   // Give the delegate a chance to hold up a stop sign.  It'll call
   1465   // use back through the passed callback if it does and that state changes.
   1466   if (!delegate_->ShouldCompleteDownload(this, state_change_notification))
   1467     return false;
   1468 
   1469   return true;
   1470 }
   1471 
   1472 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
   1473                                     ShouldUpdateObservers notify_action) {
   1474   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1475 
   1476   if (state_ == new_state)
   1477     return;
   1478 
   1479   DownloadInternalState old_state = state_;
   1480   state_ = new_state;
   1481 
   1482   switch (state_) {
   1483     case COMPLETING_INTERNAL:
   1484       bound_net_log_.AddEvent(
   1485           net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING,
   1486           base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_));
   1487       break;
   1488     case COMPLETE_INTERNAL:
   1489       bound_net_log_.AddEvent(
   1490           net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED,
   1491           base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
   1492       break;
   1493     case INTERRUPTED_INTERNAL:
   1494       bound_net_log_.AddEvent(
   1495           net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED,
   1496           base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
   1497                      received_bytes_, &hash_state_));
   1498       break;
   1499     case IN_PROGRESS_INTERNAL:
   1500       if (old_state == INTERRUPTED_INTERNAL) {
   1501         bound_net_log_.AddEvent(
   1502             net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
   1503             base::Bind(&ItemResumingNetLogCallback,
   1504                        false, last_reason_, received_bytes_, &hash_state_));
   1505       }
   1506       break;
   1507     case CANCELLED_INTERNAL:
   1508       bound_net_log_.AddEvent(
   1509           net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
   1510           base::Bind(&ItemCanceledNetLogCallback, received_bytes_,
   1511                      &hash_state_));
   1512       break;
   1513     default:
   1514       break;
   1515   }
   1516 
   1517   VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true)
   1518     << " " << InternalToExternalState(old_state)
   1519     << " " << InternalToExternalState(state_);
   1520 
   1521   bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
   1522                   state_ != COMPLETING_INTERNAL);
   1523   bool was_done = (old_state != IN_PROGRESS_INTERNAL &&
   1524                    old_state != COMPLETING_INTERNAL);
   1525   // Termination
   1526   if (is_done && !was_done)
   1527     bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
   1528 
   1529   // Resumption
   1530   if (was_done && !is_done) {
   1531     std::string file_name(target_path_.BaseName().AsUTF8Unsafe());
   1532     bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE,
   1533                               base::Bind(&ItemActivatedNetLogCallback,
   1534                                          this, SRC_ACTIVE_DOWNLOAD,
   1535                                          &file_name));
   1536   }
   1537 
   1538   if (notify_action == UPDATE_OBSERVERS)
   1539     UpdateObservers();
   1540 }
   1541 
   1542 void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
   1543   if (danger_type != danger_type_) {
   1544     bound_net_log_.AddEvent(
   1545         net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
   1546         base::Bind(&ItemCheckedNetLogCallback, danger_type));
   1547   }
   1548   danger_type_ = danger_type;
   1549 }
   1550 
   1551 void DownloadItemImpl::SetFullPath(const base::FilePath& new_path) {
   1552   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1553   VLOG(20) << __FUNCTION__ << "()"
   1554            << " new_path = \"" << new_path.value() << "\""
   1555            << " " << DebugString(true);
   1556   DCHECK(!new_path.empty());
   1557 
   1558   bound_net_log_.AddEvent(
   1559       net::NetLog::TYPE_DOWNLOAD_ITEM_RENAMED,
   1560       base::Bind(&ItemRenamedNetLogCallback, &current_path_, &new_path));
   1561 
   1562   current_path_ = new_path;
   1563 }
   1564 
   1565 void DownloadItemImpl::AutoResumeIfValid() {
   1566   DVLOG(20) << __FUNCTION__ << "() " << DebugString(true);
   1567   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1568   ResumeMode mode = GetResumeMode();
   1569 
   1570   if (mode != RESUME_MODE_IMMEDIATE_RESTART &&
   1571       mode != RESUME_MODE_IMMEDIATE_CONTINUE) {
   1572     return;
   1573   }
   1574 
   1575   auto_resume_count_++;
   1576 
   1577   ResumeInterruptedDownload();
   1578 }
   1579 
   1580 void DownloadItemImpl::ResumeInterruptedDownload() {
   1581   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1582 
   1583   // If the flag for downloads resumption isn't enabled, ignore
   1584   // this request.
   1585   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
   1586   if (!command_line.HasSwitch(switches::kEnableDownloadResumption))
   1587     return;
   1588 
   1589   // If we're not interrupted, ignore the request; our caller is drunk.
   1590   if (state_ != INTERRUPTED_INTERNAL)
   1591     return;
   1592 
   1593   // If we can't get a web contents, we can't resume the download.
   1594   // TODO(rdsmith): Find some alternative web contents to use--this
   1595   // means we can't restart a download if it's a download imported
   1596   // from the history.
   1597   if (!GetWebContents())
   1598     return;
   1599 
   1600   // Reset the appropriate state if restarting.
   1601   ResumeMode mode = GetResumeMode();
   1602   if (mode == RESUME_MODE_IMMEDIATE_RESTART ||
   1603       mode == RESUME_MODE_USER_RESTART) {
   1604     received_bytes_ = 0;
   1605     hash_state_ = "";
   1606     last_modified_time_ = "";
   1607     etag_ = "";
   1608   }
   1609 
   1610   scoped_ptr<DownloadUrlParameters> download_params(
   1611       DownloadUrlParameters::FromWebContents(GetWebContents(),
   1612                                              GetOriginalUrl()));
   1613 
   1614   download_params->set_file_path(GetFullPath());
   1615   download_params->set_offset(GetReceivedBytes());
   1616   download_params->set_hash_state(GetHashState());
   1617   download_params->set_last_modified(GetLastModifiedTime());
   1618   download_params->set_etag(GetETag());
   1619   download_params->set_callback(
   1620       base::Bind(&DownloadItemImpl::OnResumeRequestStarted,
   1621                  weak_ptr_factory_.GetWeakPtr()));
   1622 
   1623   delegate_->ResumeInterruptedDownload(download_params.Pass(), GetId());
   1624   // Just in case we were interrupted while paused.
   1625   is_paused_ = false;
   1626 
   1627   TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS);
   1628 }
   1629 
   1630 // static
   1631 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
   1632     DownloadInternalState internal_state) {
   1633   switch (internal_state) {
   1634     case IN_PROGRESS_INTERNAL:
   1635       return IN_PROGRESS;
   1636     case COMPLETING_INTERNAL:
   1637       return IN_PROGRESS;
   1638     case COMPLETE_INTERNAL:
   1639       return COMPLETE;
   1640     case CANCELLED_INTERNAL:
   1641       return CANCELLED;
   1642     case INTERRUPTED_INTERNAL:
   1643       return INTERRUPTED;
   1644     case RESUMING_INTERNAL:
   1645       return INTERRUPTED;
   1646     case MAX_DOWNLOAD_INTERNAL_STATE:
   1647       break;
   1648   }
   1649   NOTREACHED();
   1650   return MAX_DOWNLOAD_STATE;
   1651 }
   1652 
   1653 // static
   1654 DownloadItemImpl::DownloadInternalState
   1655 DownloadItemImpl::ExternalToInternalState(
   1656     DownloadState external_state) {
   1657   switch (external_state) {
   1658     case IN_PROGRESS:
   1659       return IN_PROGRESS_INTERNAL;
   1660     case COMPLETE:
   1661       return COMPLETE_INTERNAL;
   1662     case CANCELLED:
   1663       return CANCELLED_INTERNAL;
   1664     case INTERRUPTED:
   1665       return INTERRUPTED_INTERNAL;
   1666     default:
   1667       NOTREACHED();
   1668   }
   1669   return MAX_DOWNLOAD_INTERNAL_STATE;
   1670 }
   1671 
   1672 const char* DownloadItemImpl::DebugDownloadStateString(
   1673     DownloadInternalState state) {
   1674   switch (state) {
   1675     case IN_PROGRESS_INTERNAL:
   1676       return "IN_PROGRESS";
   1677     case COMPLETING_INTERNAL:
   1678       return "COMPLETING";
   1679     case COMPLETE_INTERNAL:
   1680       return "COMPLETE";
   1681     case CANCELLED_INTERNAL:
   1682       return "CANCELLED";
   1683     case INTERRUPTED_INTERNAL:
   1684       return "INTERRUPTED";
   1685     case RESUMING_INTERNAL:
   1686       return "RESUMING";
   1687     case MAX_DOWNLOAD_INTERNAL_STATE:
   1688       break;
   1689   };
   1690   NOTREACHED() << "Unknown download state " << state;
   1691   return "unknown";
   1692 }
   1693 
   1694 const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) {
   1695   switch (mode) {
   1696     case RESUME_MODE_INVALID:
   1697       return "INVALID";
   1698     case RESUME_MODE_IMMEDIATE_CONTINUE:
   1699       return "IMMEDIATE_CONTINUE";
   1700     case RESUME_MODE_IMMEDIATE_RESTART:
   1701       return "IMMEDIATE_RESTART";
   1702     case RESUME_MODE_USER_CONTINUE:
   1703       return "USER_CONTINUE";
   1704     case RESUME_MODE_USER_RESTART:
   1705       return "USER_RESTART";
   1706   }
   1707   NOTREACHED() << "Unknown resume mode " << mode;
   1708   return "unknown";
   1709 }
   1710 
   1711 }  // namespace content
   1712