• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
56 namespace content {
57 
58 namespace {
59 
DeleteDownloadedFile(const base::FilePath & path)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 
DeleteDownloadedFileDone(base::WeakPtr<DownloadItemImpl> item,const base::Callback<void (bool)> & callback,bool success)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.
DownloadFileDetach(scoped_ptr<DownloadFile> download_file)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 
DownloadFileCancel(scoped_ptr<DownloadFile> download_file)90 static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) {
91   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
92   download_file->Cancel();
93 }
94 
IsDownloadResumptionEnabled()95 bool IsDownloadResumptionEnabled() {
96   return base::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.
DownloadItemImpl(DownloadItemImplDelegate * delegate,uint32 download_id,const base::FilePath & current_path,const base::FilePath & target_path,const std::vector<GURL> & url_chain,const GURL & referrer_url,const std::string & mime_type,const std::string & original_mime_type,const base::Time & start_time,const base::Time & end_time,const std::string & etag,const std::string & last_modified,int64 received_bytes,int64 total_bytes,DownloadItem::DownloadState state,DownloadDangerType danger_type,DownloadInterruptReason interrupt_reason,bool opened,const net::BoundNetLog & bound_net_log)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 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:
DownloadItemImpl(DownloadItemImplDelegate * delegate,uint32 download_id,const DownloadCreateInfo & info,const net::BoundNetLog & bound_net_log)170 DownloadItemImpl::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:
DownloadItemImpl(DownloadItemImplDelegate * delegate,uint32 download_id,const base::FilePath & path,const GURL & url,const std::string & mime_type,scoped_ptr<DownloadRequestHandleInterface> request_handle,const net::BoundNetLog & bound_net_log)229 DownloadItemImpl::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 
~DownloadItemImpl()274 DownloadItemImpl::~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 
AddObserver(Observer * observer)286 void DownloadItemImpl::AddObserver(Observer* observer) {
287   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
288 
289   observers_.AddObserver(observer);
290 }
291 
RemoveObserver(Observer * observer)292 void DownloadItemImpl::RemoveObserver(Observer* observer) {
293   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
294 
295   observers_.RemoveObserver(observer);
296 }
297 
UpdateObservers()298 void DownloadItemImpl::UpdateObservers() {
299   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
300 
301   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
302 }
303 
ValidateDangerousDownload()304 void 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 
StealDangerousDownload(const AcquireFileCallback & callback)328 void 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 
Pause()347 void 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 
Resume()359 void 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 
Cancel(bool user_cancel)386 void 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 
Remove()436 void 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 
OpenDownload()449 void 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 
ShowDownloadInShell()474 void DownloadItemImpl::ShowDownloadInShell() {
475   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
476 
477   delegate_->ShowDownloadInShell(this);
478 }
479 
GetId() const480 uint32 DownloadItemImpl::GetId() const {
481   return download_id_;
482 }
483 
GetState() const484 DownloadItem::DownloadState DownloadItemImpl::GetState() const {
485   return InternalToExternalState(state_);
486 }
487 
GetLastReason() const488 DownloadInterruptReason DownloadItemImpl::GetLastReason() const {
489   return last_reason_;
490 }
491 
IsPaused() const492 bool DownloadItemImpl::IsPaused() const {
493   return is_paused_;
494 }
495 
IsTemporary() const496 bool DownloadItemImpl::IsTemporary() const {
497   return is_temporary_;
498 }
499 
CanResume() const500 bool 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 
IsDone() const518 bool 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 
GetURL() const541 const GURL& DownloadItemImpl::GetURL() const {
542   return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.back();
543 }
544 
GetUrlChain() const545 const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const {
546   return url_chain_;
547 }
548 
GetOriginalUrl() const549 const 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 
GetReferrerUrl() const555 const GURL& DownloadItemImpl::GetReferrerUrl() const {
556   return referrer_url_;
557 }
558 
GetTabUrl() const559 const GURL& DownloadItemImpl::GetTabUrl() const {
560   return tab_url_;
561 }
562 
GetTabReferrerUrl() const563 const GURL& DownloadItemImpl::GetTabReferrerUrl() const {
564   return tab_referrer_url_;
565 }
566 
GetSuggestedFilename() const567 std::string DownloadItemImpl::GetSuggestedFilename() const {
568   return suggested_filename_;
569 }
570 
GetContentDisposition() const571 std::string DownloadItemImpl::GetContentDisposition() const {
572   return content_disposition_;
573 }
574 
GetMimeType() const575 std::string DownloadItemImpl::GetMimeType() const {
576   return mime_type_;
577 }
578 
GetOriginalMimeType() const579 std::string DownloadItemImpl::GetOriginalMimeType() const {
580   return original_mime_type_;
581 }
582 
GetRemoteAddress() const583 std::string DownloadItemImpl::GetRemoteAddress() const {
584   return remote_address_;
585 }
586 
HasUserGesture() const587 bool DownloadItemImpl::HasUserGesture() const {
588   return has_user_gesture_;
589 };
590 
GetTransitionType() const591 ui::PageTransition DownloadItemImpl::GetTransitionType() const {
592   return transition_type_;
593 };
594 
GetLastModifiedTime() const595 const std::string& DownloadItemImpl::GetLastModifiedTime() const {
596   return last_modified_time_;
597 }
598 
GetETag() const599 const std::string& DownloadItemImpl::GetETag() const {
600   return etag_;
601 }
602 
IsSavePackageDownload() const603 bool DownloadItemImpl::IsSavePackageDownload() const {
604   return is_save_package_download_;
605 }
606 
GetFullPath() const607 const base::FilePath& DownloadItemImpl::GetFullPath() const {
608   return current_path_;
609 }
610 
GetTargetFilePath() const611 const base::FilePath& DownloadItemImpl::GetTargetFilePath() const {
612   return target_path_;
613 }
614 
GetForcedFilePath() const615 const 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 
GetFileNameToReportUser() const621 base::FilePath DownloadItemImpl::GetFileNameToReportUser() const {
622   if (!display_name_.empty())
623     return display_name_;
624   return target_path_.BaseName();
625 }
626 
GetTargetDisposition() const627 DownloadItem::TargetDisposition DownloadItemImpl::GetTargetDisposition() const {
628   return target_disposition_;
629 }
630 
GetHash() const631 const std::string& DownloadItemImpl::GetHash() const {
632   return hash_;
633 }
634 
GetHashState() const635 const std::string& DownloadItemImpl::GetHashState() const {
636   return hash_state_;
637 }
638 
GetFileExternallyRemoved() const639 bool DownloadItemImpl::GetFileExternallyRemoved() const {
640   return file_externally_removed_;
641 }
642 
DeleteFile(const base::Callback<void (bool)> & callback)643 void 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 
IsDangerous() const668 bool 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 
GetDangerType() const684 DownloadDangerType DownloadItemImpl::GetDangerType() const {
685   return danger_type_;
686 }
687 
TimeRemaining(base::TimeDelta * remaining) const688 bool 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 
CurrentSpeed() const701 int64 DownloadItemImpl::CurrentSpeed() const {
702   if (is_paused_)
703     return 0;
704   return bytes_per_sec_;
705 }
706 
PercentComplete() const707 int 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 
AllDataSaved() const716 bool DownloadItemImpl::AllDataSaved() const {
717   return all_data_saved_;
718 }
719 
GetTotalBytes() const720 int64 DownloadItemImpl::GetTotalBytes() const {
721   return total_bytes_;
722 }
723 
GetReceivedBytes() const724 int64 DownloadItemImpl::GetReceivedBytes() const {
725   return received_bytes_;
726 }
727 
GetStartTime() const728 base::Time DownloadItemImpl::GetStartTime() const {
729   return start_time_;
730 }
731 
GetEndTime() const732 base::Time DownloadItemImpl::GetEndTime() const {
733   return end_time_;
734 }
735 
CanShowInFolder()736 bool 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 
CanOpenDownload()742 bool 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 
ShouldOpenFileBasedOnExtension()751 bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() {
752   return delegate_->ShouldOpenFileBasedOnExtension(GetTargetFilePath());
753 }
754 
GetOpenWhenComplete() const755 bool DownloadItemImpl::GetOpenWhenComplete() const {
756   return open_when_complete_;
757 }
758 
GetAutoOpened()759 bool DownloadItemImpl::GetAutoOpened() {
760   return auto_opened_;
761 }
762 
GetOpened() const763 bool DownloadItemImpl::GetOpened() const {
764   return opened_;
765 }
766 
GetBrowserContext() const767 BrowserContext* DownloadItemImpl::GetBrowserContext() const {
768   return delegate_->GetBrowserContext();
769 }
770 
GetWebContents() const771 WebContents* 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 
OnContentCheckCompleted(DownloadDangerType danger_type)781 void 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 
SetOpenWhenComplete(bool open)790 void DownloadItemImpl::SetOpenWhenComplete(bool open) {
791   open_when_complete_ = open;
792 }
793 
SetIsTemporary(bool temporary)794 void DownloadItemImpl::SetIsTemporary(bool temporary) {
795   is_temporary_ = temporary;
796 }
797 
SetOpened(bool opened)798 void DownloadItemImpl::SetOpened(bool opened) {
799   opened_ = opened;
800 }
801 
SetDisplayName(const base::FilePath & name)802 void DownloadItemImpl::SetDisplayName(const base::FilePath& name) {
803   display_name_ = name;
804 }
805 
DebugString(bool verbose) const806 std::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 
GetResumeMode() const866 DownloadItemImpl::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 
MergeOriginInfoOnResume(const DownloadCreateInfo & new_create_info)939 void 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 
NotifyRemoved()983 void DownloadItemImpl::NotifyRemoved() {
984   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this));
985 }
986 
OnDownloadedFileRemoved()987 void DownloadItemImpl::OnDownloadedFileRemoved() {
988   file_externally_removed_ = true;
989   VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
990   UpdateObservers();
991 }
992 
993 base::WeakPtr<DownloadDestinationObserver>
DestinationObserverAsWeakPtr()994 DownloadItemImpl::DestinationObserverAsWeakPtr() {
995   return weak_ptr_factory_.GetWeakPtr();
996 }
997 
GetBoundNetLog() const998 const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
999   return bound_net_log_;
1000 }
1001 
SetTotalBytes(int64 total_bytes)1002 void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
1003   total_bytes_ = total_bytes;
1004 }
1005 
OnAllDataSaved(const std::string & final_hash)1006 void 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 
MarkAsComplete()1021 void 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 
DestinationUpdate(int64 bytes_so_far,int64 bytes_per_sec,const std::string & hash_state)1029 void 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 
DestinationError(DownloadInterruptReason reason)1066 void 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 
DestinationCompleted(const std::string & final_hash)1076 void 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 
Init(bool active,DownloadType download_type)1086 void 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.
Start(scoped_ptr<DownloadFile> file,scoped_ptr<DownloadRequestHandleInterface> req_handle)1122 void 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 
OnDownloadFileInitialized(DownloadInterruptReason result)1152 void 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.
OnDownloadTargetDetermined(const base::FilePath & target_path,TargetDisposition disposition,DownloadDangerType danger_type,const base::FilePath & intermediate_path)1175 void 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 
OnDownloadRenamedToIntermediateName(DownloadInterruptReason reason,const base::FilePath & full_path)1240 void 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.
MaybeCompleteDownload()1276 void 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.
OnDownloadCompleting()1300 void 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 
OnDownloadRenamedToFinalName(DownloadInterruptReason reason,const base::FilePath & full_path)1335 void 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 
DelayedDownloadOpened(bool auto_opened)1388 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
1389   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1390 
1391   auto_opened_ = auto_opened;
1392   Completed();
1393 }
1394 
Completed()1395 void 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 
OnResumeRequestStarted(DownloadItem * item,DownloadInterruptReason interrupt_reason)1421 void 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.
Interrupt(DownloadInterruptReason reason)1440 void 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 
ReleaseDownloadFile(bool destroy_file)1500 void 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 
IsDownloadReadyForCompletion(const base::Closure & state_change_notification)1525 bool 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 
TransitionTo(DownloadInternalState new_state,ShouldUpdateObservers notify_action)1560 void 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 
SetDangerType(DownloadDangerType danger_type)1630 void 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 
SetFullPath(const base::FilePath & new_path)1651 void 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 
AutoResumeIfValid()1665 void 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 
ResumeInterruptedDownload()1680 void 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
InternalToExternalState(DownloadInternalState internal_state)1732 DownloadItem::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
1755 DownloadItemImpl::DownloadInternalState
ExternalToInternalState(DownloadState external_state)1756 DownloadItemImpl::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 
DebugDownloadStateString(DownloadInternalState state)1773 const 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 
DebugResumeModeString(ResumeMode mode)1795 const 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