• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • 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 
DeleteDownloadedFile(const FilePath & path)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 
DebugSafetyStateString(DownloadItem::SafetyState state)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 
DebugDownloadStateString(DownloadItem::DownloadState state)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 
GetSafetyState(bool dangerous_file,bool dangerous_url)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.
GetDangerType(bool dangerous_file,bool dangerous_url)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.
DownloadItem(DownloadManager * download_manager,const DownloadCreateInfo & info)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:
DownloadItem(DownloadManager * download_manager,const DownloadCreateInfo & info,bool is_otr)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:
DownloadItem(DownloadManager * download_manager,const FilePath & path,const GURL & url,bool is_otr)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 
~DownloadItem()230 DownloadItem::~DownloadItem() {
231   state_ = REMOVING;
232   UpdateObservers();
233 }
234 
AddObserver(Observer * observer)235 void DownloadItem::AddObserver(Observer* observer) {
236   observers_.AddObserver(observer);
237 }
238 
RemoveObserver(Observer * observer)239 void DownloadItem::RemoveObserver(Observer* observer) {
240   observers_.RemoveObserver(observer);
241 }
242 
UpdateObservers()243 void DownloadItem::UpdateObservers() {
244   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
245 }
246 
CanOpenDownload()247 bool DownloadItem::CanOpenDownload() {
248   return !Extension::IsExtension(target_name_);
249 }
250 
ShouldOpenFileBasedOnExtension()251 bool DownloadItem::ShouldOpenFileBasedOnExtension() {
252   return download_manager_->ShouldOpenFileBasedOnExtension(
253       GetUserVerifiedFilePath());
254 }
255 
OpenFilesBasedOnExtension(bool open)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 
OpenDownload()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 
ShowDownloadInShell()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 
DangerousDownloadValidated()299 void DownloadItem::DangerousDownloadValidated() {
300   UMA_HISTOGRAM_ENUMERATION("Download.DangerousDownloadValidated",
301                             danger_type_,
302                             DANGEROUS_TYPE_MAX);
303   download_manager_->DangerousDownloadValidated(this);
304 }
305 
UpdateSize(int64 bytes_so_far)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 
StartProgressTimer()315 void DownloadItem::StartProgressTimer() {
316   update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdateTimeMs), this,
317                       &DownloadItem::UpdateObservers);
318 }
319 
StopProgressTimer()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.
Update(int64 bytes_so_far)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.
Cancel(bool update_history)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 
MarkAsComplete()354 void DownloadItem::MarkAsComplete() {
355   DCHECK(all_data_saved_);
356   state_ = COMPLETE;
357   UpdateObservers();
358 }
359 
OnAllDataSaved(int64 size)360 void DownloadItem::OnAllDataSaved(int64 size) {
361   DCHECK(!all_data_saved_);
362   all_data_saved_ = true;
363   UpdateSize(size);
364   StopProgressTimer();
365 }
366 
Completed()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 
Interrupted(int64 size,int os_error)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 
Delete(DeleteReason reason)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 
Remove()430 void DownloadItem::Remove() {
431   Cancel(true);
432   state_ = REMOVING;
433   download_manager_->RemoveDownload(db_handle_);
434   // We have now been deleted.
435 }
436 
TimeRemaining(base::TimeDelta * remaining) const437 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 
CurrentSpeed() const450 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 
PercentComplete() const458 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 
Rename(const FilePath & full_path)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 
TogglePause()473 void DownloadItem::TogglePause() {
474   DCHECK(IsInProgress());
475   download_manager_->PauseDownload(id_, !is_paused_);
476   is_paused_ = !is_paused_;
477   UpdateObservers();
478 }
479 
OnNameFinalized()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 
OnDownloadCompleting(DownloadFileManager * file_manager)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 
OnDownloadRenamedToFinalName(const FilePath & full_path)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 
MatchesQuery(const string16 & query) const532 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 
SetFileCheckResults(const FilePath & path,bool is_dangerous_file,bool is_dangerous_url,int path_uniquifier,bool prompt,bool is_extension_install,const FilePath & original_name)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 
GetTargetFilePath() const597 FilePath DownloadItem::GetTargetFilePath() const {
598   return full_path_.DirName().Append(target_name_);
599 }
600 
GetFileNameToReportUser() const601 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 
GetUserVerifiedFilePath() const610 FilePath DownloadItem::GetUserVerifiedFilePath() const {
611   if (safety_state_ == DownloadItem::SAFE)
612     return GetTargetFilePath();
613   return full_path_;
614 }
615 
Init(bool start_timer)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.
IsPartialDownload() const626 bool DownloadItem::IsPartialDownload() const {
627   return (state_ == IN_PROGRESS);
628 }
629 
IsInProgress() const630 bool DownloadItem::IsInProgress() const {
631   return (state_ == IN_PROGRESS);
632 }
633 
IsCancelled() const634 bool DownloadItem::IsCancelled() const {
635   return (state_ == CANCELLED) || (state_ == INTERRUPTED);
636 }
637 
IsInterrupted() const638 bool DownloadItem::IsInterrupted() const {
639   return (state_ == INTERRUPTED);
640 }
641 
IsComplete() const642 bool DownloadItem::IsComplete() const {
643   return state() == COMPLETE;
644 }
645 
DebugString(bool verbose) const646 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