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