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