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