Home | History | Annotate | Download | only in download
      1 // Copyright (c) 2011 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 #include "chrome/browser/download/download_item.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/file_util.h"
      9 #include "base/format_macros.h"
     10 #include "base/logging.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/stringprintf.h"
     13 #include "base/timer.h"
     14 #include "base/utf_string_conversions.h"
     15 #include "net/base/net_util.h"
     16 #include "chrome/browser/download/download_extensions.h"
     17 #include "chrome/browser/download/download_file_manager.h"
     18 #include "chrome/browser/download/download_history.h"
     19 #include "chrome/browser/download/download_manager.h"
     20 #include "chrome/browser/download/download_prefs.h"
     21 #include "chrome/browser/download/download_util.h"
     22 #include "chrome/browser/history/download_create_info.h"
     23 #include "chrome/browser/platform_util.h"
     24 #include "chrome/browser/prefs/pref_service.h"
     25 #include "chrome/browser/profiles/profile.h"
     26 #include "chrome/common/extensions/extension.h"
     27 #include "chrome/common/pref_names.h"
     28 #include "content/browser/browser_thread.h"
     29 #include "ui/base/l10n/l10n_util.h"
     30 
     31 // A DownloadItem normally goes through the following states:
     32 //      * Created (when download starts)
     33 //      * Made visible to consumers (e.g. Javascript) after the
     34 //        destination file has been determined.
     35 //      * Entered into the history database.
     36 //      * Made visible in the download shelf.
     37 //      * All data is saved.  Note that the actual data download occurs
     38 //        in parallel with the above steps, but until those steps are
     39 //        complete, completion of the data download will be ignored.
     40 //      * Download file is renamed to its final name, and possibly
     41 //        auto-opened.
     42 // TODO(rdsmith): This progress should be reflected in
     43 // DownloadItem::DownloadState and a state transition table/state diagram.
     44 //
     45 // TODO(rdsmith): This description should be updated to reflect the cancel
     46 // pathways.
     47 
     48 namespace {
     49 
     50 // Update frequency (milliseconds).
     51 const int kUpdateTimeMs = 1000;
     52 
     53 void DeleteDownloadedFile(const FilePath& path) {
     54   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     55 
     56   // Make sure we only delete files.
     57   if (!file_util::DirectoryExists(path))
     58     file_util::Delete(path, false);
     59 }
     60 
     61 const char* DebugSafetyStateString(DownloadItem::SafetyState state) {
     62   switch (state) {
     63     case DownloadItem::SAFE:
     64       return "SAFE";
     65     case DownloadItem::DANGEROUS:
     66       return "DANGEROUS";
     67     case DownloadItem::DANGEROUS_BUT_VALIDATED:
     68       return "DANGEROUS_BUT_VALIDATED";
     69     default:
     70       NOTREACHED() << "Unknown safety state " << state;
     71       return "unknown";
     72   };
     73 }
     74 
     75 const char* DebugDownloadStateString(DownloadItem::DownloadState state) {
     76   switch (state) {
     77     case DownloadItem::IN_PROGRESS:
     78       return "IN_PROGRESS";
     79     case DownloadItem::COMPLETE:
     80       return "COMPLETE";
     81     case DownloadItem::CANCELLED:
     82       return "CANCELLED";
     83     case DownloadItem::REMOVING:
     84       return "REMOVING";
     85     case DownloadItem::INTERRUPTED:
     86       return "INTERRUPTED";
     87     default:
     88       NOTREACHED() << "Unknown download state " << state;
     89       return "unknown";
     90   };
     91 }
     92 
     93 DownloadItem::SafetyState GetSafetyState(bool dangerous_file,
     94                                          bool dangerous_url) {
     95   return (dangerous_url || dangerous_file) ?
     96       DownloadItem::DANGEROUS : DownloadItem::SAFE;
     97 }
     98 
     99 // Note: When a download has both |dangerous_file| and |dangerous_url| set,
    100 // danger type is set to DANGEROUS_URL since the risk of dangerous URL
    101 // overweights that of dangerous file type.
    102 DownloadItem::DangerType GetDangerType(bool dangerous_file,
    103                                        bool dangerous_url) {
    104   if (dangerous_url) {
    105     // dangerous URL overweights dangerous file. We check dangerous URL first.
    106     return DownloadItem::DANGEROUS_URL;
    107   } else if (dangerous_file) {
    108     return DownloadItem::DANGEROUS_FILE;
    109   }
    110   return DownloadItem::NOT_DANGEROUS;
    111 }
    112 
    113 }  // namespace
    114 
    115 // Constructor for reading from the history service.
    116 DownloadItem::DownloadItem(DownloadManager* download_manager,
    117                            const DownloadCreateInfo& info)
    118     : id_(-1),
    119       full_path_(info.path),
    120       path_uniquifier_(0),
    121       url_chain_(info.url_chain),
    122       referrer_url_(info.referrer_url),
    123       mime_type_(info.mime_type),
    124       original_mime_type_(info.original_mime_type),
    125       total_bytes_(info.total_bytes),
    126       received_bytes_(info.received_bytes),
    127       start_tick_(base::TimeTicks()),
    128       state_(static_cast<DownloadState>(info.state)),
    129       start_time_(info.start_time),
    130       db_handle_(info.db_handle),
    131       download_manager_(download_manager),
    132       is_paused_(false),
    133       open_when_complete_(false),
    134       safety_state_(SAFE),
    135       danger_type_(NOT_DANGEROUS),
    136       auto_opened_(false),
    137       target_name_(info.original_name),
    138       render_process_id_(-1),
    139       request_id_(-1),
    140       save_as_(false),
    141       is_otr_(false),
    142       is_extension_install_(info.is_extension_install),
    143       name_finalized_(false),
    144       is_temporary_(false),
    145       all_data_saved_(false),
    146       opened_(false) {
    147   if (IsInProgress())
    148     state_ = CANCELLED;
    149   if (IsComplete())
    150     all_data_saved_ = true;
    151   Init(false /* don't start progress timer */);
    152 }
    153 
    154 // Constructing for a regular download:
    155 DownloadItem::DownloadItem(DownloadManager* download_manager,
    156                            const DownloadCreateInfo& info,
    157                            bool is_otr)
    158     : id_(info.download_id),
    159       full_path_(info.path),
    160       path_uniquifier_(info.path_uniquifier),
    161       url_chain_(info.url_chain),
    162       referrer_url_(info.referrer_url),
    163       mime_type_(info.mime_type),
    164       original_mime_type_(info.original_mime_type),
    165       total_bytes_(info.total_bytes),
    166       received_bytes_(0),
    167       last_os_error_(0),
    168       start_tick_(base::TimeTicks::Now()),
    169       state_(IN_PROGRESS),
    170       start_time_(info.start_time),
    171       db_handle_(DownloadHistory::kUninitializedHandle),
    172       download_manager_(download_manager),
    173       is_paused_(false),
    174       open_when_complete_(false),
    175       safety_state_(GetSafetyState(info.is_dangerous_file,
    176                                    info.is_dangerous_url)),
    177       danger_type_(GetDangerType(info.is_dangerous_file,
    178                                  info.is_dangerous_url)),
    179       auto_opened_(false),
    180       target_name_(info.original_name),
    181       render_process_id_(info.child_id),
    182       request_id_(info.request_id),
    183       save_as_(info.prompt_user_for_save_location),
    184       is_otr_(is_otr),
    185       is_extension_install_(info.is_extension_install),
    186       name_finalized_(false),
    187       is_temporary_(!info.save_info.file_path.empty()),
    188       all_data_saved_(false),
    189       opened_(false) {
    190   Init(true /* start progress timer */);
    191 }
    192 
    193 // Constructing for the "Save Page As..." feature:
    194 DownloadItem::DownloadItem(DownloadManager* download_manager,
    195                            const FilePath& path,
    196                            const GURL& url,
    197                            bool is_otr)
    198     : id_(1),
    199       full_path_(path),
    200       path_uniquifier_(0),
    201       url_chain_(1, url),
    202       referrer_url_(GURL()),
    203       mime_type_(std::string()),
    204       original_mime_type_(std::string()),
    205       total_bytes_(0),
    206       received_bytes_(0),
    207       last_os_error_(0),
    208       start_tick_(base::TimeTicks::Now()),
    209       state_(IN_PROGRESS),
    210       start_time_(base::Time::Now()),
    211       db_handle_(DownloadHistory::kUninitializedHandle),
    212       download_manager_(download_manager),
    213       is_paused_(false),
    214       open_when_complete_(false),
    215       safety_state_(SAFE),
    216       danger_type_(NOT_DANGEROUS),
    217       auto_opened_(false),
    218       render_process_id_(-1),
    219       request_id_(-1),
    220       save_as_(false),
    221       is_otr_(is_otr),
    222       is_extension_install_(false),
    223       name_finalized_(false),
    224       is_temporary_(false),
    225       all_data_saved_(false),
    226       opened_(false) {
    227   Init(true /* start progress timer */);
    228 }
    229 
    230 DownloadItem::~DownloadItem() {
    231   state_ = REMOVING;
    232   UpdateObservers();
    233 }
    234 
    235 void DownloadItem::AddObserver(Observer* observer) {
    236   observers_.AddObserver(observer);
    237 }
    238 
    239 void DownloadItem::RemoveObserver(Observer* observer) {
    240   observers_.RemoveObserver(observer);
    241 }
    242 
    243 void DownloadItem::UpdateObservers() {
    244   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
    245 }
    246 
    247 bool DownloadItem::CanOpenDownload() {
    248   return !Extension::IsExtension(target_name_);
    249 }
    250 
    251 bool DownloadItem::ShouldOpenFileBasedOnExtension() {
    252   return download_manager_->ShouldOpenFileBasedOnExtension(
    253       GetUserVerifiedFilePath());
    254 }
    255 
    256 void DownloadItem::OpenFilesBasedOnExtension(bool open) {
    257   DownloadPrefs* prefs = download_manager_->download_prefs();
    258   if (open)
    259     prefs->EnableAutoOpenBasedOnExtension(GetUserVerifiedFilePath());
    260   else
    261     prefs->DisableAutoOpenBasedOnExtension(GetUserVerifiedFilePath());
    262 }
    263 
    264 void DownloadItem::OpenDownload() {
    265   if (IsPartialDownload()) {
    266     open_when_complete_ = !open_when_complete_;
    267   } else if (IsComplete()) {
    268     opened_ = true;
    269     FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this));
    270     if (is_extension_install()) {
    271       download_util::OpenChromeExtension(download_manager_->profile(),
    272                                          download_manager_,
    273                                          *this);
    274       return;
    275     }
    276 #if defined(OS_MACOSX)
    277     // Mac OS X requires opening downloads on the UI thread.
    278     platform_util::OpenItem(full_path());
    279 #else
    280     BrowserThread::PostTask(
    281         BrowserThread::FILE, FROM_HERE,
    282         NewRunnableFunction(&platform_util::OpenItem, full_path()));
    283 #endif
    284   }
    285 }
    286 
    287 void DownloadItem::ShowDownloadInShell() {
    288 #if defined(OS_MACOSX)
    289   // Mac needs to run this operation on the UI thread.
    290   platform_util::ShowItemInFolder(full_path());
    291 #else
    292   BrowserThread::PostTask(
    293       BrowserThread::FILE, FROM_HERE,
    294       NewRunnableFunction(&platform_util::ShowItemInFolder,
    295                           full_path()));
    296 #endif
    297 }
    298 
    299 void DownloadItem::DangerousDownloadValidated() {
    300   UMA_HISTOGRAM_ENUMERATION("Download.DangerousDownloadValidated",
    301                             danger_type_,
    302                             DANGEROUS_TYPE_MAX);
    303   download_manager_->DangerousDownloadValidated(this);
    304 }
    305 
    306 void DownloadItem::UpdateSize(int64 bytes_so_far) {
    307   received_bytes_ = bytes_so_far;
    308 
    309   // If we've received more data than we were expecting (bad server info?),
    310   // revert to 'unknown size mode'.
    311   if (received_bytes_ > total_bytes_)
    312     total_bytes_ = 0;
    313 }
    314 
    315 void DownloadItem::StartProgressTimer() {
    316   update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdateTimeMs), this,
    317                       &DownloadItem::UpdateObservers);
    318 }
    319 
    320 void DownloadItem::StopProgressTimer() {
    321   update_timer_.Stop();
    322 }
    323 
    324 // Updates from the download thread may have been posted while this download
    325 // was being cancelled in the UI thread, so we'll accept them unless we're
    326 // complete.
    327 void DownloadItem::Update(int64 bytes_so_far) {
    328   if (!IsInProgress()) {
    329     NOTREACHED();
    330     return;
    331   }
    332   UpdateSize(bytes_so_far);
    333   UpdateObservers();
    334 }
    335 
    336 // Triggered by a user action.
    337 void DownloadItem::Cancel(bool update_history) {
    338   VLOG(20) << __FUNCTION__ << "()" << " download = " << DebugString(true);
    339   if (!IsPartialDownload()) {
    340     // Small downloads might be complete before this method has
    341     // a chance to run.
    342     return;
    343   }
    344 
    345   download_util::RecordDownloadCount(download_util::CANCELLED_COUNT);
    346 
    347   state_ = CANCELLED;
    348   UpdateObservers();
    349   StopProgressTimer();
    350   if (update_history)
    351     download_manager_->DownloadCancelled(id_);
    352 }
    353 
    354 void DownloadItem::MarkAsComplete() {
    355   DCHECK(all_data_saved_);
    356   state_ = COMPLETE;
    357   UpdateObservers();
    358 }
    359 
    360 void DownloadItem::OnAllDataSaved(int64 size) {
    361   DCHECK(!all_data_saved_);
    362   all_data_saved_ = true;
    363   UpdateSize(size);
    364   StopProgressTimer();
    365 }
    366 
    367 void DownloadItem::Completed() {
    368   VLOG(20) << " " << __FUNCTION__ << "() "
    369            << DebugString(false);
    370 
    371   download_util::RecordDownloadCount(download_util::COMPLETED_COUNT);
    372 
    373   // Handle chrome extensions explicitly and skip the shell execute.
    374   if (is_extension_install()) {
    375     download_util::OpenChromeExtension(download_manager_->profile(),
    376                                        download_manager_,
    377                                        *this);
    378     auto_opened_ = true;
    379   } else if (open_when_complete() ||
    380              download_manager_->ShouldOpenFileBasedOnExtension(
    381                  GetUserVerifiedFilePath()) ||
    382              is_temporary()) {
    383     // If the download is temporary, like in drag-and-drop, do not open it but
    384     // we still need to set it auto-opened so that it can be removed from the
    385     // download shelf.
    386     if (!is_temporary())
    387       OpenDownload();
    388     auto_opened_ = true;
    389   }
    390 
    391   DCHECK(all_data_saved_);
    392   state_ = COMPLETE;
    393   UpdateObservers();
    394   download_manager_->DownloadCompleted(id());
    395 }
    396 
    397 void DownloadItem::Interrupted(int64 size, int os_error) {
    398   if (!IsInProgress())
    399     return;
    400   state_ = INTERRUPTED;
    401   last_os_error_ = os_error;
    402   UpdateSize(size);
    403   StopProgressTimer();
    404   UpdateObservers();
    405 }
    406 
    407 void DownloadItem::Delete(DeleteReason reason) {
    408   switch (reason) {
    409     case DELETE_DUE_TO_USER_DISCARD:
    410       UMA_HISTOGRAM_ENUMERATION("Download.UserDiscard",
    411                                 danger_type_,
    412                                 DANGEROUS_TYPE_MAX);
    413       break;
    414     case DELETE_DUE_TO_BROWSER_SHUTDOWN:
    415       UMA_HISTOGRAM_ENUMERATION("Download.Discard",
    416                                 danger_type_,
    417                                 DANGEROUS_TYPE_MAX);
    418       break;
    419     default:
    420       NOTREACHED();
    421   }
    422 
    423   BrowserThread::PostTask(
    424       BrowserThread::FILE, FROM_HERE,
    425       NewRunnableFunction(&DeleteDownloadedFile, full_path_));
    426   Remove();
    427   // We have now been deleted.
    428 }
    429 
    430 void DownloadItem::Remove() {
    431   Cancel(true);
    432   state_ = REMOVING;
    433   download_manager_->RemoveDownload(db_handle_);
    434   // We have now been deleted.
    435 }
    436 
    437 bool DownloadItem::TimeRemaining(base::TimeDelta* remaining) const {
    438   if (total_bytes_ <= 0)
    439     return false;  // We never received the content_length for this download.
    440 
    441   int64 speed = CurrentSpeed();
    442   if (speed == 0)
    443     return false;
    444 
    445   *remaining =
    446       base::TimeDelta::FromSeconds((total_bytes_ - received_bytes_) / speed);
    447   return true;
    448 }
    449 
    450 int64 DownloadItem::CurrentSpeed() const {
    451   if (is_paused_)
    452     return 0;
    453   base::TimeDelta diff = base::TimeTicks::Now() - start_tick_;
    454   int64 diff_ms = diff.InMilliseconds();
    455   return diff_ms == 0 ? 0 : received_bytes_ * 1000 / diff_ms;
    456 }
    457 
    458 int DownloadItem::PercentComplete() const {
    459   int percent = -1;
    460   if (total_bytes_ > 0)
    461     percent = static_cast<int>(received_bytes_ * 100.0 / total_bytes_);
    462   return percent;
    463 }
    464 
    465 void DownloadItem::Rename(const FilePath& full_path) {
    466   VLOG(20) << " " << __FUNCTION__ << "()"
    467            << " full_path = \"" << full_path.value() << "\""
    468            << DebugString(true);
    469   DCHECK(!full_path.empty());
    470   full_path_ = full_path;
    471 }
    472 
    473 void DownloadItem::TogglePause() {
    474   DCHECK(IsInProgress());
    475   download_manager_->PauseDownload(id_, !is_paused_);
    476   is_paused_ = !is_paused_;
    477   UpdateObservers();
    478 }
    479 
    480 void DownloadItem::OnNameFinalized() {
    481   VLOG(20) << " " << __FUNCTION__ << "() "
    482            << DebugString(true);
    483   name_finalized_ = true;
    484 
    485   // We can't reach this point in the code without having received all the
    486   // data, so it's safe to move to the COMPLETE state.
    487   DCHECK(all_data_saved_);
    488   state_ = COMPLETE;
    489   UpdateObservers();
    490   download_manager_->DownloadCompleted(id());
    491 }
    492 
    493 void DownloadItem::OnDownloadCompleting(DownloadFileManager* file_manager) {
    494   VLOG(20) << " " << __FUNCTION__ << "() "
    495            << " needs rename = " << NeedsRename()
    496            << " " << DebugString(true);
    497   DCHECK_NE(DANGEROUS, safety_state());
    498   DCHECK(file_manager);
    499 
    500   if (NeedsRename()) {
    501     BrowserThread::PostTask(
    502         BrowserThread::FILE, FROM_HERE,
    503         NewRunnableMethod(
    504             file_manager, &DownloadFileManager::RenameCompletingDownloadFile,
    505             id(), GetTargetFilePath(), safety_state() == SAFE));
    506     return;
    507   } else {
    508     name_finalized_ = true;
    509   }
    510 
    511   Completed();
    512 
    513   BrowserThread::PostTask(
    514       BrowserThread::FILE, FROM_HERE,
    515       NewRunnableMethod(
    516           file_manager, &DownloadFileManager::CompleteDownload, id()));
    517 }
    518 
    519 void DownloadItem::OnDownloadRenamedToFinalName(const FilePath& full_path) {
    520   VLOG(20) << " " << __FUNCTION__ << "()"
    521            << " full_path = " << full_path.value()
    522            << " needed rename = " << NeedsRename()
    523            << " " << DebugString(false);
    524   DCHECK(NeedsRename());
    525 
    526   Rename(full_path);
    527   OnNameFinalized();
    528 
    529   Completed();
    530 }
    531 
    532 bool DownloadItem::MatchesQuery(const string16& query) const {
    533   if (query.empty())
    534     return true;
    535 
    536   DCHECK_EQ(query, l10n_util::ToLower(query));
    537 
    538   string16 url_raw(l10n_util::ToLower(UTF8ToUTF16(url().spec())));
    539   if (url_raw.find(query) != string16::npos)
    540     return true;
    541 
    542   // TODO(phajdan.jr): write a test case for the following code.
    543   // A good test case would be:
    544   //   "/\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xbd\xa0\xe5\xa5\xbd",
    545   //   L"/\x4f60\x597d\x4f60\x597d",
    546   //   "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD"
    547   PrefService* prefs = download_manager_->profile()->GetPrefs();
    548   std::string languages(prefs->GetString(prefs::kAcceptLanguages));
    549   string16 url_formatted(l10n_util::ToLower(net::FormatUrl(url(), languages)));
    550   if (url_formatted.find(query) != string16::npos)
    551     return true;
    552 
    553   string16 path(l10n_util::ToLower(full_path().LossyDisplayName()));
    554   // This shouldn't just do a substring match; it is wrong for Unicode
    555   // due to normalization and we have a fancier search-query system
    556   // used elsewhere.
    557   // http://code.google.com/p/chromium/issues/detail?id=71982
    558   if (path.find(query) != string16::npos)
    559     return true;
    560 
    561   return false;
    562 }
    563 
    564 void DownloadItem::SetFileCheckResults(const FilePath& path,
    565                                        bool is_dangerous_file,
    566                                        bool is_dangerous_url,
    567                                        int path_uniquifier,
    568                                        bool prompt,
    569                                        bool is_extension_install,
    570                                        const FilePath& original_name) {
    571   VLOG(20) << " " << __FUNCTION__ << "()"
    572            << " path = \"" << path.value() << "\""
    573            << " is_dangerous_file = " << is_dangerous_file
    574            << " is_dangerous_url = " << is_dangerous_url
    575            << " path_uniquifier = " << path_uniquifier
    576            << " prompt = " << prompt
    577            << " is_extension_install = " << is_extension_install
    578            << " path = \"" << path.value() << "\""
    579            << " original_name = \"" << original_name.value() << "\""
    580            << " " << DebugString(true);
    581   // Make sure the initial file name is set only once.
    582   DCHECK(full_path_.empty());
    583   DCHECK(!path.empty());
    584 
    585   full_path_ = path;
    586   safety_state_ = GetSafetyState(is_dangerous_file, is_dangerous_url);
    587   danger_type_ = GetDangerType(is_dangerous_file, is_dangerous_url);
    588   path_uniquifier_ = path_uniquifier;
    589   save_as_ = prompt;
    590   is_extension_install_ = is_extension_install;
    591   target_name_ = original_name;
    592 
    593   if (target_name_.value().empty())
    594     target_name_ = full_path_.BaseName();
    595 }
    596 
    597 FilePath DownloadItem::GetTargetFilePath() const {
    598   return full_path_.DirName().Append(target_name_);
    599 }
    600 
    601 FilePath DownloadItem::GetFileNameToReportUser() const {
    602   if (path_uniquifier_ > 0) {
    603     FilePath name(target_name_);
    604     download_util::AppendNumberToPath(&name, path_uniquifier_);
    605     return name;
    606   }
    607   return target_name_;
    608 }
    609 
    610 FilePath DownloadItem::GetUserVerifiedFilePath() const {
    611   if (safety_state_ == DownloadItem::SAFE)
    612     return GetTargetFilePath();
    613   return full_path_;
    614 }
    615 
    616 void DownloadItem::Init(bool start_timer) {
    617   if (target_name_.value().empty())
    618     target_name_ = full_path_.BaseName();
    619   if (start_timer)
    620     StartProgressTimer();
    621   VLOG(20) << " " << __FUNCTION__ << "() " << DebugString(true);
    622 }
    623 
    624 // TODO(ahendrickson) -- Move |INTERRUPTED| from |IsCancelled()| to
    625 // |IsPartialDownload()|, when resuming interrupted downloads is implemented.
    626 bool DownloadItem::IsPartialDownload() const {
    627   return (state_ == IN_PROGRESS);
    628 }
    629 
    630 bool DownloadItem::IsInProgress() const {
    631   return (state_ == IN_PROGRESS);
    632 }
    633 
    634 bool DownloadItem::IsCancelled() const {
    635   return (state_ == CANCELLED) || (state_ == INTERRUPTED);
    636 }
    637 
    638 bool DownloadItem::IsInterrupted() const {
    639   return (state_ == INTERRUPTED);
    640 }
    641 
    642 bool DownloadItem::IsComplete() const {
    643   return state() == COMPLETE;
    644 }
    645 
    646 std::string DownloadItem::DebugString(bool verbose) const {
    647   std::string description =
    648       base::StringPrintf("{ id_ = %d"
    649                          " state = %s",
    650                          id_,
    651                          DebugDownloadStateString(state()));
    652 
    653   if (verbose) {
    654     description += base::StringPrintf(
    655         " db_handle = %" PRId64
    656         " total_bytes = %" PRId64
    657         " is_paused = " "%c"
    658         " is_extension_install = " "%c"
    659         " is_otr = " "%c"
    660         " safety_state = " "%s"
    661         " url = " "\"%s\""
    662         " target_name_ = \"%" PRFilePath "\""
    663         " full_path = \"%" PRFilePath "\"",
    664         db_handle(),
    665         total_bytes(),
    666         is_paused() ? 'T' : 'F',
    667         is_extension_install() ? 'T' : 'F',
    668         is_otr() ? 'T' : 'F',
    669         DebugSafetyStateString(safety_state()),
    670         url().spec().c_str(),
    671         target_name_.value().c_str(),
    672         full_path().value().c_str());
    673   } else {
    674     description += base::StringPrintf(" url = \"%s\"", url().spec().c_str());
    675   }
    676 
    677   description += " }";
    678 
    679   return description;
    680 }
    681