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