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/files/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 base::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_(ui::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_(ui::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 ui::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     case DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
    931     case DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
    932       mode = RESUME_MODE_INVALID;
    933       break;
    934   }
    935 
    936   return mode;
    937 }
    938 
    939 void DownloadItemImpl::MergeOriginInfoOnResume(
    940     const DownloadCreateInfo& new_create_info) {
    941   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    942   DCHECK_EQ(RESUMING_INTERNAL, state_);
    943   DCHECK(!new_create_info.url_chain.empty());
    944 
    945   // We are going to tack on any new redirects to our list of redirects.
    946   // When a download is resumed, the URL used for the resumption request is the
    947   // one at the end of the previous redirect chain. Tacking additional redirects
    948   // to the end of this chain ensures that:
    949   // - If the download needs to be resumed again, the ETag/Last-Modified headers
    950   //   will be used with the last server that sent them to us.
    951   // - The redirect chain contains all the servers that were involved in this
    952   //   download since the initial request, in order.
    953   std::vector<GURL>::const_iterator chain_iter =
    954       new_create_info.url_chain.begin();
    955   if (*chain_iter == url_chain_.back())
    956     ++chain_iter;
    957 
    958   // Record some stats. If the precondition failed (the server returned
    959   // HTTP_PRECONDITION_FAILED), then the download will automatically retried as
    960   // a full request rather than a partial. Full restarts clobber validators.
    961   int origin_state = 0;
    962   if (chain_iter != new_create_info.url_chain.end())
    963     origin_state |= ORIGIN_STATE_ON_RESUMPTION_ADDITIONAL_REDIRECTS;
    964   if (etag_ != new_create_info.etag ||
    965       last_modified_time_ != new_create_info.last_modified)
    966     origin_state |= ORIGIN_STATE_ON_RESUMPTION_VALIDATORS_CHANGED;
    967   if (content_disposition_ != new_create_info.content_disposition)
    968     origin_state |= ORIGIN_STATE_ON_RESUMPTION_CONTENT_DISPOSITION_CHANGED;
    969   RecordOriginStateOnResumption(new_create_info.save_info->offset != 0,
    970                                 origin_state);
    971 
    972   url_chain_.insert(
    973       url_chain_.end(), chain_iter, new_create_info.url_chain.end());
    974   etag_ = new_create_info.etag;
    975   last_modified_time_ = new_create_info.last_modified;
    976   content_disposition_ = new_create_info.content_disposition;
    977 
    978   // Don't update observers. This method is expected to be called just before a
    979   // DownloadFile is created and Start() is called. The observers will be
    980   // notified when the download transitions to the IN_PROGRESS state.
    981 }
    982 
    983 void DownloadItemImpl::NotifyRemoved() {
    984   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this));
    985 }
    986 
    987 void DownloadItemImpl::OnDownloadedFileRemoved() {
    988   file_externally_removed_ = true;
    989   VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
    990   UpdateObservers();
    991 }
    992 
    993 base::WeakPtr<DownloadDestinationObserver>
    994 DownloadItemImpl::DestinationObserverAsWeakPtr() {
    995   return weak_ptr_factory_.GetWeakPtr();
    996 }
    997 
    998 const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
    999   return bound_net_log_;
   1000 }
   1001 
   1002 void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
   1003   total_bytes_ = total_bytes;
   1004 }
   1005 
   1006 void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
   1007   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1008 
   1009   DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
   1010   DCHECK(!all_data_saved_);
   1011   all_data_saved_ = true;
   1012   VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
   1013 
   1014   // Store final hash and null out intermediate serialized hash state.
   1015   hash_ = final_hash;
   1016   hash_state_ = "";
   1017 
   1018   UpdateObservers();
   1019 }
   1020 
   1021 void DownloadItemImpl::MarkAsComplete() {
   1022   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1023 
   1024   DCHECK(all_data_saved_);
   1025   end_time_ = base::Time::Now();
   1026   TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS);
   1027 }
   1028 
   1029 void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far,
   1030                                          int64 bytes_per_sec,
   1031                                          const std::string& hash_state) {
   1032   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1033   VLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far
   1034            << " per_sec=" << bytes_per_sec << " download=" << DebugString(true);
   1035 
   1036   if (GetState() != IN_PROGRESS) {
   1037     // Ignore if we're no longer in-progress.  This can happen if we race a
   1038     // Cancel on the UI thread with an update on the FILE thread.
   1039     //
   1040     // TODO(rdsmith): Arguably we should let this go through, as this means
   1041     // the download really did get further than we know before it was
   1042     // cancelled.  But the gain isn't very large, and the code is more
   1043     // fragile if it has to support in progress updates in a non-in-progress
   1044     // state.  This issue should be readdressed when we revamp performance
   1045     // reporting.
   1046     return;
   1047   }
   1048   bytes_per_sec_ = bytes_per_sec;
   1049   hash_state_ = hash_state;
   1050   received_bytes_ = bytes_so_far;
   1051 
   1052   // If we've received more data than we were expecting (bad server info?),
   1053   // revert to 'unknown size mode'.
   1054   if (received_bytes_ > total_bytes_)
   1055     total_bytes_ = 0;
   1056 
   1057   if (bound_net_log_.IsLogging()) {
   1058     bound_net_log_.AddEvent(
   1059         net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
   1060         net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
   1061   }
   1062 
   1063   UpdateObservers();
   1064 }
   1065 
   1066 void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) {
   1067   // Postpone recognition of this error until after file name determination
   1068   // has completed and the intermediate file has been renamed to simplify
   1069   // resumption conditions.
   1070   if (current_path_.empty() || target_path_.empty())
   1071     destination_error_ = reason;
   1072   else
   1073     Interrupt(reason);
   1074 }
   1075 
   1076 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
   1077   VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
   1078   if (GetState() != IN_PROGRESS)
   1079     return;
   1080   OnAllDataSaved(final_hash);
   1081   MaybeCompleteDownload();
   1082 }
   1083 
   1084 // **** Download progression cascade
   1085 
   1086 void DownloadItemImpl::Init(bool active,
   1087                             DownloadType download_type) {
   1088   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1089 
   1090   if (active)
   1091     RecordDownloadCount(START_COUNT);
   1092 
   1093   std::string file_name;
   1094   if (download_type == SRC_HISTORY_IMPORT) {
   1095     // target_path_ works for History and Save As versions.
   1096     file_name = target_path_.AsUTF8Unsafe();
   1097   } else {
   1098     // See if it's set programmatically.
   1099     file_name = forced_file_path_.AsUTF8Unsafe();
   1100     // Possibly has a 'download' attribute for the anchor.
   1101     if (file_name.empty())
   1102       file_name = suggested_filename_;
   1103     // From the URL file name.
   1104     if (file_name.empty())
   1105       file_name = GetURL().ExtractFileName();
   1106   }
   1107 
   1108   base::Callback<base::Value*(net::NetLog::LogLevel)> active_data = base::Bind(
   1109       &ItemActivatedNetLogCallback, this, download_type, &file_name);
   1110   if (active) {
   1111     bound_net_log_.BeginEvent(
   1112         net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
   1113   } else {
   1114     bound_net_log_.AddEvent(
   1115         net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
   1116   }
   1117 
   1118   VLOG(20) << __FUNCTION__ << "() " << DebugString(true);
   1119 }
   1120 
   1121 // We're starting the download.
   1122 void DownloadItemImpl::Start(
   1123     scoped_ptr<DownloadFile> file,
   1124     scoped_ptr<DownloadRequestHandleInterface> req_handle) {
   1125   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1126   DCHECK(!download_file_.get());
   1127   DCHECK(file.get());
   1128   DCHECK(req_handle.get());
   1129 
   1130   download_file_ = file.Pass();
   1131   request_handle_ = req_handle.Pass();
   1132 
   1133   if (GetState() == CANCELLED) {
   1134     // The download was in the process of resuming when it was cancelled. Don't
   1135     // proceed.
   1136     ReleaseDownloadFile(true);
   1137     request_handle_->CancelRequest();
   1138     return;
   1139   }
   1140 
   1141   TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS);
   1142 
   1143   BrowserThread::PostTask(
   1144       BrowserThread::FILE, FROM_HERE,
   1145       base::Bind(&DownloadFile::Initialize,
   1146                  // Safe because we control download file lifetime.
   1147                  base::Unretained(download_file_.get()),
   1148                  base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
   1149                             weak_ptr_factory_.GetWeakPtr())));
   1150 }
   1151 
   1152 void DownloadItemImpl::OnDownloadFileInitialized(
   1153     DownloadInterruptReason result) {
   1154   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1155   if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
   1156     Interrupt(result);
   1157     // TODO(rdsmith/asanka): Arguably we should show this in the UI, but
   1158     // it's not at all clear what to show--we haven't done filename
   1159     // determination, so we don't know what name to display.  OTOH,
   1160     // the failure mode of not showing the DI if the file initialization
   1161     // fails isn't a good one.  Can we hack up a name based on the
   1162     // URLRequest?  We'll need to make sure that initialization happens
   1163     // properly.  Possibly the right thing is to have the UI handle
   1164     // this case specially.
   1165     return;
   1166   }
   1167 
   1168   delegate_->DetermineDownloadTarget(
   1169       this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
   1170                        weak_ptr_factory_.GetWeakPtr()));
   1171 }
   1172 
   1173 // Called by delegate_ when the download target path has been
   1174 // determined.
   1175 void DownloadItemImpl::OnDownloadTargetDetermined(
   1176     const base::FilePath& target_path,
   1177     TargetDisposition disposition,
   1178     DownloadDangerType danger_type,
   1179     const base::FilePath& intermediate_path) {
   1180   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1181 
   1182   // If the |target_path| is empty, then we consider this download to be
   1183   // canceled.
   1184   if (target_path.empty()) {
   1185     Cancel(true);
   1186     return;
   1187   }
   1188 
   1189   // TODO(rdsmith,asanka): We are ignoring the possibility that the download
   1190   // has been interrupted at this point until we finish the intermediate
   1191   // rename and set the full path.  That's dangerous, because we might race
   1192   // with resumption, either manual (because the interrupt is visible to the
   1193   // UI) or automatic.  If we keep the "ignore an error on download until file
   1194   // name determination complete" semantics, we need to make sure that the
   1195   // error is kept completely invisible until that point.
   1196 
   1197   VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition
   1198            << " " << danger_type << " " << DebugString(true);
   1199 
   1200   target_path_ = target_path;
   1201   target_disposition_ = disposition;
   1202   SetDangerType(danger_type);
   1203 
   1204   // We want the intermediate and target paths to refer to the same directory so
   1205   // that they are both on the same device and subject to same
   1206   // space/permission/availability constraints.
   1207   DCHECK(intermediate_path.DirName() == target_path.DirName());
   1208 
   1209   // During resumption, we may choose to proceed with the same intermediate
   1210   // file. No rename is necessary if our intermediate file already has the
   1211   // correct name.
   1212   //
   1213   // The intermediate name may change from its original value during filename
   1214   // determination on resumption, for example if the reason for the interruption
   1215   // was the download target running out space, resulting in a user prompt.
   1216   if (intermediate_path == current_path_) {
   1217     OnDownloadRenamedToIntermediateName(DOWNLOAD_INTERRUPT_REASON_NONE,
   1218                                         intermediate_path);
   1219     return;
   1220   }
   1221 
   1222   // Rename to intermediate name.
   1223   // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a
   1224   //               spurious rename when we can just rename to the final
   1225   //               filename. Unnecessary renames may cause bugs like
   1226   //               http://crbug.com/74187.
   1227   DCHECK(!is_save_package_download_);
   1228   DCHECK(download_file_.get());
   1229   DownloadFile::RenameCompletionCallback callback =
   1230       base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName,
   1231                  weak_ptr_factory_.GetWeakPtr());
   1232   BrowserThread::PostTask(
   1233       BrowserThread::FILE, FROM_HERE,
   1234       base::Bind(&DownloadFile::RenameAndUniquify,
   1235                  // Safe because we control download file lifetime.
   1236                  base::Unretained(download_file_.get()),
   1237                  intermediate_path, callback));
   1238 }
   1239 
   1240 void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
   1241     DownloadInterruptReason reason,
   1242     const base::FilePath& full_path) {
   1243   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1244   VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
   1245 
   1246   if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) {
   1247     // Process destination error.  If both |reason| and |destination_error_|
   1248     // refer to actual errors, we want to use the |destination_error_| as the
   1249     // argument to the Interrupt() routine, as it happened first.
   1250     if (reason == DOWNLOAD_INTERRUPT_REASON_NONE)
   1251       SetFullPath(full_path);
   1252     Interrupt(destination_error_);
   1253     destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
   1254   } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
   1255     Interrupt(reason);
   1256     // All file errors result in file deletion above; no need to cleanup.  The
   1257     // current_path_ should be empty. Resuming this download will force a
   1258     // restart and a re-doing of filename determination.
   1259     DCHECK(current_path_.empty());
   1260   } else {
   1261     SetFullPath(full_path);
   1262     UpdateObservers();
   1263     MaybeCompleteDownload();
   1264   }
   1265 }
   1266 
   1267 // When SavePackage downloads MHTML to GData (see
   1268 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
   1269 // does for non-SavePackage downloads, but SavePackage downloads never satisfy
   1270 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
   1271 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage
   1272 // notices that the upload has completed and runs its normal Finish() pathway.
   1273 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes
   1274 // downloads. SavePackage always uses its own Finish() to mark downloads
   1275 // complete.
   1276 void DownloadItemImpl::MaybeCompleteDownload() {
   1277   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1278   DCHECK(!is_save_package_download_);
   1279 
   1280   if (!IsDownloadReadyForCompletion(
   1281           base::Bind(&DownloadItemImpl::MaybeCompleteDownload,
   1282                      weak_ptr_factory_.GetWeakPtr())))
   1283     return;
   1284 
   1285   // TODO(rdsmith): DCHECK that we only pass through this point
   1286   // once per download.  The natural way to do this is by a state
   1287   // transition on the DownloadItem.
   1288 
   1289   // Confirm we're in the proper set of states to be here;
   1290   // have all data, have a history handle, (validated or safe).
   1291   DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
   1292   DCHECK(!IsDangerous());
   1293   DCHECK(all_data_saved_);
   1294 
   1295   OnDownloadCompleting();
   1296 }
   1297 
   1298 // Called by MaybeCompleteDownload() when it has determined that the download
   1299 // is ready for completion.
   1300 void DownloadItemImpl::OnDownloadCompleting() {
   1301   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1302 
   1303   if (state_ != IN_PROGRESS_INTERNAL)
   1304     return;
   1305 
   1306   VLOG(20) << __FUNCTION__ << "()"
   1307            << " " << DebugString(true);
   1308   DCHECK(!GetTargetFilePath().empty());
   1309   DCHECK(!IsDangerous());
   1310 
   1311   // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration.
   1312   if (is_save_package_download_) {
   1313     // Avoid doing anything on the file thread; there's nothing we control
   1314     // there.
   1315     // Strictly speaking, this skips giving the embedder a chance to open
   1316     // the download.  But on a save package download, there's no real
   1317     // concept of opening.
   1318     Completed();
   1319     return;
   1320   }
   1321 
   1322   DCHECK(download_file_.get());
   1323   // Unilaterally rename; even if it already has the right name,
   1324   // we need theannotation.
   1325   DownloadFile::RenameCompletionCallback callback =
   1326       base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName,
   1327                  weak_ptr_factory_.GetWeakPtr());
   1328   BrowserThread::PostTask(
   1329       BrowserThread::FILE, FROM_HERE,
   1330       base::Bind(&DownloadFile::RenameAndAnnotate,
   1331                  base::Unretained(download_file_.get()),
   1332                  GetTargetFilePath(), callback));
   1333 }
   1334 
   1335 void DownloadItemImpl::OnDownloadRenamedToFinalName(
   1336     DownloadInterruptReason reason,
   1337     const base::FilePath& full_path) {
   1338   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1339   DCHECK(!is_save_package_download_);
   1340 
   1341   // If a cancel or interrupt hit, we'll cancel the DownloadFile, which
   1342   // will result in deleting the file on the file thread.  So we don't
   1343   // care about the name having been changed.
   1344   if (state_ != IN_PROGRESS_INTERNAL)
   1345     return;
   1346 
   1347   VLOG(20) << __FUNCTION__ << "()"
   1348            << " full_path = \"" << full_path.value() << "\""
   1349            << " " << DebugString(false);
   1350 
   1351   if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
   1352     Interrupt(reason);
   1353 
   1354     // All file errors should have resulted in in file deletion above. On
   1355     // resumption we will need to re-do filename determination.
   1356     DCHECK(current_path_.empty());
   1357     return;
   1358   }
   1359 
   1360   DCHECK(target_path_ == full_path);
   1361 
   1362   if (full_path != current_path_) {
   1363     // full_path is now the current and target file path.
   1364     DCHECK(!full_path.empty());
   1365     SetFullPath(full_path);
   1366   }
   1367 
   1368   // Complete the download and release the DownloadFile.
   1369   DCHECK(download_file_.get());
   1370   ReleaseDownloadFile(false);
   1371 
   1372   // We're not completely done with the download item yet, but at this
   1373   // point we're committed to complete the download.  Cancels (or Interrupts,
   1374   // though it's not clear how they could happen) after this point will be
   1375   // ignored.
   1376   TransitionTo(COMPLETING_INTERNAL, DONT_UPDATE_OBSERVERS);
   1377 
   1378   if (delegate_->ShouldOpenDownload(
   1379           this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened,
   1380                            weak_ptr_factory_.GetWeakPtr()))) {
   1381     Completed();
   1382   } else {
   1383     delegate_delayed_complete_ = true;
   1384     UpdateObservers();
   1385   }
   1386 }
   1387 
   1388 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
   1389   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1390 
   1391   auto_opened_ = auto_opened;
   1392   Completed();
   1393 }
   1394 
   1395 void DownloadItemImpl::Completed() {
   1396   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1397 
   1398   VLOG(20) << __FUNCTION__ << "() " << DebugString(false);
   1399 
   1400   DCHECK(all_data_saved_);
   1401   end_time_ = base::Time::Now();
   1402   TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS);
   1403   RecordDownloadCompleted(start_tick_, received_bytes_);
   1404 
   1405   if (auto_opened_) {
   1406     // If it was already handled by the delegate, do nothing.
   1407   } else if (GetOpenWhenComplete() ||
   1408              ShouldOpenFileBasedOnExtension() ||
   1409              IsTemporary()) {
   1410     // If the download is temporary, like in drag-and-drop, do not open it but
   1411     // we still need to set it auto-opened so that it can be removed from the
   1412     // download shelf.
   1413     if (!IsTemporary())
   1414       OpenDownload();
   1415 
   1416     auto_opened_ = true;
   1417     UpdateObservers();
   1418   }
   1419 }
   1420 
   1421 void DownloadItemImpl::OnResumeRequestStarted(
   1422     DownloadItem* item,
   1423     DownloadInterruptReason interrupt_reason) {
   1424   // If |item| is not NULL, then Start() has been called already, and nothing
   1425   // more needs to be done here.
   1426   if (item) {
   1427     DCHECK_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
   1428     DCHECK_EQ(static_cast<DownloadItem*>(this), item);
   1429     return;
   1430   }
   1431   // Otherwise, the request failed without passing through
   1432   // DownloadResourceHandler::OnResponseStarted.
   1433   DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
   1434   Interrupt(interrupt_reason);
   1435 }
   1436 
   1437 // **** End of Download progression cascade
   1438 
   1439 // An error occurred somewhere.
   1440 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
   1441   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1442   DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason);
   1443 
   1444   // Somewhat counter-intuitively, it is possible for us to receive an
   1445   // interrupt after we've already been interrupted.  The generation of
   1446   // interrupts from the file thread Renames and the generation of
   1447   // interrupts from disk writes go through two different mechanisms (driven
   1448   // by rename requests from UI thread and by write requests from IO thread,
   1449   // respectively), and since we choose not to keep state on the File thread,
   1450   // this is the place where the races collide.  It's also possible for
   1451   // interrupts to race with cancels.
   1452 
   1453   // Whatever happens, the first one to hit the UI thread wins.
   1454   if (state_ != IN_PROGRESS_INTERNAL && state_ != RESUMING_INTERNAL)
   1455     return;
   1456 
   1457   last_reason_ = reason;
   1458 
   1459   ResumeMode resume_mode = GetResumeMode();
   1460 
   1461   if (state_ == IN_PROGRESS_INTERNAL) {
   1462     // Cancel (delete file) if:
   1463     // 1) we're going to restart.
   1464     // 2) Resumption isn't possible (download was cancelled or blocked due to
   1465     //    security restrictions).
   1466     // 3) Resumption isn't enabled.
   1467     // No point in leaving data around we aren't going to use.
   1468     ReleaseDownloadFile(resume_mode == RESUME_MODE_IMMEDIATE_RESTART ||
   1469                         resume_mode == RESUME_MODE_USER_RESTART ||
   1470                         resume_mode == RESUME_MODE_INVALID ||
   1471                         !IsDownloadResumptionEnabled());
   1472 
   1473     // Cancel the originating URL request.
   1474     request_handle_->CancelRequest();
   1475   } else {
   1476     DCHECK(!download_file_.get());
   1477   }
   1478 
   1479   // Reset all data saved, as even if we did save all the data we're going
   1480   // to go through another round of downloading when we resume.
   1481   // There's a potential problem here in the abstract, as if we did download
   1482   // all the data and then run into a continuable error, on resumption we
   1483   // won't download any more data.  However, a) there are currently no
   1484   // continuable errors that can occur after we download all the data, and
   1485   // b) if there were, that would probably simply result in a null range
   1486   // request, which would generate a DestinationCompleted() notification
   1487   // from the DownloadFile, which would behave properly with setting
   1488   // all_data_saved_ to false here.
   1489   all_data_saved_ = false;
   1490 
   1491   TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS);
   1492   RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
   1493   if (!GetWebContents())
   1494     RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
   1495 
   1496   AutoResumeIfValid();
   1497   UpdateObservers();
   1498 }
   1499 
   1500 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) {
   1501   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1502 
   1503   if (destroy_file) {
   1504     BrowserThread::PostTask(
   1505         BrowserThread::FILE, FROM_HERE,
   1506         // Will be deleted at end of task execution.
   1507         base::Bind(&DownloadFileCancel, base::Passed(&download_file_)));
   1508     // Avoid attempting to reuse the intermediate file by clearing out
   1509     // current_path_.
   1510     current_path_.clear();
   1511   } else {
   1512     BrowserThread::PostTask(
   1513         BrowserThread::FILE,
   1514         FROM_HERE,
   1515         base::Bind(base::IgnoreResult(&DownloadFileDetach),
   1516                    // Will be deleted at end of task execution.
   1517                    base::Passed(&download_file_)));
   1518   }
   1519   // Don't accept any more messages from the DownloadFile, and null
   1520   // out any previous "all data received".  This also breaks links to
   1521   // other entities we've given out weak pointers to.
   1522   weak_ptr_factory_.InvalidateWeakPtrs();
   1523 }
   1524 
   1525 bool DownloadItemImpl::IsDownloadReadyForCompletion(
   1526     const base::Closure& state_change_notification) {
   1527   // If we don't have all the data, the download is not ready for
   1528   // completion.
   1529   if (!AllDataSaved())
   1530     return false;
   1531 
   1532   // If the download is dangerous, but not yet validated, it's not ready for
   1533   // completion.
   1534   if (IsDangerous())
   1535     return false;
   1536 
   1537   // If the download isn't active (e.g. has been cancelled) it's not
   1538   // ready for completion.
   1539   if (state_ != IN_PROGRESS_INTERNAL)
   1540     return false;
   1541 
   1542   // If the target filename hasn't been determined, then it's not ready for
   1543   // completion. This is checked in ReadyForDownloadCompletionDone().
   1544   if (GetTargetFilePath().empty())
   1545     return false;
   1546 
   1547   // This is checked in NeedsRename(). Without this conditional,
   1548   // browser_tests:DownloadTest.DownloadMimeType fails the DCHECK.
   1549   if (target_path_.DirName() != current_path_.DirName())
   1550     return false;
   1551 
   1552   // Give the delegate a chance to hold up a stop sign.  It'll call
   1553   // use back through the passed callback if it does and that state changes.
   1554   if (!delegate_->ShouldCompleteDownload(this, state_change_notification))
   1555     return false;
   1556 
   1557   return true;
   1558 }
   1559 
   1560 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
   1561                                     ShouldUpdateObservers notify_action) {
   1562   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1563 
   1564   if (state_ == new_state)
   1565     return;
   1566 
   1567   DownloadInternalState old_state = state_;
   1568   state_ = new_state;
   1569 
   1570   switch (state_) {
   1571     case COMPLETING_INTERNAL:
   1572       bound_net_log_.AddEvent(
   1573           net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING,
   1574           base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_));
   1575       break;
   1576     case COMPLETE_INTERNAL:
   1577       bound_net_log_.AddEvent(
   1578           net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED,
   1579           base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
   1580       break;
   1581     case INTERRUPTED_INTERNAL:
   1582       bound_net_log_.AddEvent(
   1583           net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED,
   1584           base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
   1585                      received_bytes_, &hash_state_));
   1586       break;
   1587     case IN_PROGRESS_INTERNAL:
   1588       if (old_state == INTERRUPTED_INTERNAL) {
   1589         bound_net_log_.AddEvent(
   1590             net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
   1591             base::Bind(&ItemResumingNetLogCallback,
   1592                        false, last_reason_, received_bytes_, &hash_state_));
   1593       }
   1594       break;
   1595     case CANCELLED_INTERNAL:
   1596       bound_net_log_.AddEvent(
   1597           net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
   1598           base::Bind(&ItemCanceledNetLogCallback, received_bytes_,
   1599                      &hash_state_));
   1600       break;
   1601     default:
   1602       break;
   1603   }
   1604 
   1605   VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true)
   1606     << " " << InternalToExternalState(old_state)
   1607     << " " << InternalToExternalState(state_);
   1608 
   1609   bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
   1610                   state_ != COMPLETING_INTERNAL);
   1611   bool was_done = (old_state != IN_PROGRESS_INTERNAL &&
   1612                    old_state != COMPLETING_INTERNAL);
   1613   // Termination
   1614   if (is_done && !was_done)
   1615     bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
   1616 
   1617   // Resumption
   1618   if (was_done && !is_done) {
   1619     std::string file_name(target_path_.BaseName().AsUTF8Unsafe());
   1620     bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE,
   1621                               base::Bind(&ItemActivatedNetLogCallback,
   1622                                          this, SRC_ACTIVE_DOWNLOAD,
   1623                                          &file_name));
   1624   }
   1625 
   1626   if (notify_action == UPDATE_OBSERVERS)
   1627     UpdateObservers();
   1628 }
   1629 
   1630 void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
   1631   if (danger_type != danger_type_) {
   1632     bound_net_log_.AddEvent(
   1633         net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
   1634         base::Bind(&ItemCheckedNetLogCallback, danger_type));
   1635   }
   1636   // Only record the Malicious UMA stat if it's going from {not malicious} ->
   1637   // {malicious}.
   1638   if ((danger_type_ == DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
   1639        danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
   1640        danger_type_ == DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
   1641        danger_type_ == DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT) &&
   1642       (danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
   1643        danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
   1644        danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
   1645        danger_type == DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED)) {
   1646     RecordMaliciousDownloadClassified(danger_type);
   1647   }
   1648   danger_type_ = danger_type;
   1649 }
   1650 
   1651 void DownloadItemImpl::SetFullPath(const base::FilePath& new_path) {
   1652   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1653   VLOG(20) << __FUNCTION__ << "()"
   1654            << " new_path = \"" << new_path.value() << "\""
   1655            << " " << DebugString(true);
   1656   DCHECK(!new_path.empty());
   1657 
   1658   bound_net_log_.AddEvent(
   1659       net::NetLog::TYPE_DOWNLOAD_ITEM_RENAMED,
   1660       base::Bind(&ItemRenamedNetLogCallback, &current_path_, &new_path));
   1661 
   1662   current_path_ = new_path;
   1663 }
   1664 
   1665 void DownloadItemImpl::AutoResumeIfValid() {
   1666   DVLOG(20) << __FUNCTION__ << "() " << DebugString(true);
   1667   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1668   ResumeMode mode = GetResumeMode();
   1669 
   1670   if (mode != RESUME_MODE_IMMEDIATE_RESTART &&
   1671       mode != RESUME_MODE_IMMEDIATE_CONTINUE) {
   1672     return;
   1673   }
   1674 
   1675   auto_resume_count_++;
   1676 
   1677   ResumeInterruptedDownload();
   1678 }
   1679 
   1680 void DownloadItemImpl::ResumeInterruptedDownload() {
   1681   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1682 
   1683   // If the flag for downloads resumption isn't enabled, ignore
   1684   // this request.
   1685   const base::CommandLine& command_line =
   1686       *base::CommandLine::ForCurrentProcess();
   1687   if (!command_line.HasSwitch(switches::kEnableDownloadResumption))
   1688     return;
   1689 
   1690   // If we're not interrupted, ignore the request; our caller is drunk.
   1691   if (state_ != INTERRUPTED_INTERNAL)
   1692     return;
   1693 
   1694   // If we can't get a web contents, we can't resume the download.
   1695   // TODO(rdsmith): Find some alternative web contents to use--this
   1696   // means we can't restart a download if it's a download imported
   1697   // from the history.
   1698   if (!GetWebContents())
   1699     return;
   1700 
   1701   // Reset the appropriate state if restarting.
   1702   ResumeMode mode = GetResumeMode();
   1703   if (mode == RESUME_MODE_IMMEDIATE_RESTART ||
   1704       mode == RESUME_MODE_USER_RESTART) {
   1705     received_bytes_ = 0;
   1706     hash_state_ = "";
   1707     last_modified_time_ = "";
   1708     etag_ = "";
   1709   }
   1710 
   1711   scoped_ptr<DownloadUrlParameters> download_params(
   1712       DownloadUrlParameters::FromWebContents(GetWebContents(),
   1713                                              GetOriginalUrl()));
   1714 
   1715   download_params->set_file_path(GetFullPath());
   1716   download_params->set_offset(GetReceivedBytes());
   1717   download_params->set_hash_state(GetHashState());
   1718   download_params->set_last_modified(GetLastModifiedTime());
   1719   download_params->set_etag(GetETag());
   1720   download_params->set_callback(
   1721       base::Bind(&DownloadItemImpl::OnResumeRequestStarted,
   1722                  weak_ptr_factory_.GetWeakPtr()));
   1723 
   1724   delegate_->ResumeInterruptedDownload(download_params.Pass(), GetId());
   1725   // Just in case we were interrupted while paused.
   1726   is_paused_ = false;
   1727 
   1728   TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS);
   1729 }
   1730 
   1731 // static
   1732 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
   1733     DownloadInternalState internal_state) {
   1734   switch (internal_state) {
   1735     case IN_PROGRESS_INTERNAL:
   1736       return IN_PROGRESS;
   1737     case COMPLETING_INTERNAL:
   1738       return IN_PROGRESS;
   1739     case COMPLETE_INTERNAL:
   1740       return COMPLETE;
   1741     case CANCELLED_INTERNAL:
   1742       return CANCELLED;
   1743     case INTERRUPTED_INTERNAL:
   1744       return INTERRUPTED;
   1745     case RESUMING_INTERNAL:
   1746       return INTERRUPTED;
   1747     case MAX_DOWNLOAD_INTERNAL_STATE:
   1748       break;
   1749   }
   1750   NOTREACHED();
   1751   return MAX_DOWNLOAD_STATE;
   1752 }
   1753 
   1754 // static
   1755 DownloadItemImpl::DownloadInternalState
   1756 DownloadItemImpl::ExternalToInternalState(
   1757     DownloadState external_state) {
   1758   switch (external_state) {
   1759     case IN_PROGRESS:
   1760       return IN_PROGRESS_INTERNAL;
   1761     case COMPLETE:
   1762       return COMPLETE_INTERNAL;
   1763     case CANCELLED:
   1764       return CANCELLED_INTERNAL;
   1765     case INTERRUPTED:
   1766       return INTERRUPTED_INTERNAL;
   1767     default:
   1768       NOTREACHED();
   1769   }
   1770   return MAX_DOWNLOAD_INTERNAL_STATE;
   1771 }
   1772 
   1773 const char* DownloadItemImpl::DebugDownloadStateString(
   1774     DownloadInternalState state) {
   1775   switch (state) {
   1776     case IN_PROGRESS_INTERNAL:
   1777       return "IN_PROGRESS";
   1778     case COMPLETING_INTERNAL:
   1779       return "COMPLETING";
   1780     case COMPLETE_INTERNAL:
   1781       return "COMPLETE";
   1782     case CANCELLED_INTERNAL:
   1783       return "CANCELLED";
   1784     case INTERRUPTED_INTERNAL:
   1785       return "INTERRUPTED";
   1786     case RESUMING_INTERNAL:
   1787       return "RESUMING";
   1788     case MAX_DOWNLOAD_INTERNAL_STATE:
   1789       break;
   1790   };
   1791   NOTREACHED() << "Unknown download state " << state;
   1792   return "unknown";
   1793 }
   1794 
   1795 const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) {
   1796   switch (mode) {
   1797     case RESUME_MODE_INVALID:
   1798       return "INVALID";
   1799     case RESUME_MODE_IMMEDIATE_CONTINUE:
   1800       return "IMMEDIATE_CONTINUE";
   1801     case RESUME_MODE_IMMEDIATE_RESTART:
   1802       return "IMMEDIATE_RESTART";
   1803     case RESUME_MODE_USER_CONTINUE:
   1804       return "USER_CONTINUE";
   1805     case RESUME_MODE_USER_RESTART:
   1806       return "USER_RESTART";
   1807   }
   1808   NOTREACHED() << "Unknown resume mode " << mode;
   1809   return "unknown";
   1810 }
   1811 
   1812 }  // namespace content
   1813