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