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