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
13 // the 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 "components/download/public/common/download_item_impl.h"
25 
26 #include <memory>
27 #include <utility>
28 #include <vector>
29 
30 #include "base/bind.h"
31 #include "base/files/file_util.h"
32 #include "base/format_macros.h"
33 #include "base/guid.h"
34 #include "base/json/string_escape.h"
35 #include "base/logging.h"
36 #include "base/metrics/histogram_macros.h"
37 #include "base/optional.h"
38 #include "base/stl_util.h"
39 #include "base/strings/string_piece.h"
40 #include "base/strings/string_util.h"
41 #include "base/strings/stringprintf.h"
42 #include "base/strings/utf_string_conversions.h"
43 #include "base/task_runner_util.h"
44 #include "base/trace_event/memory_usage_estimator.h"
45 #include "build/build_config.h"
46 #include "components/download/internal/common/download_job_impl.h"
47 #include "components/download/internal/common/parallel_download_utils.h"
48 #include "components/download/public/common/download_danger_type.h"
49 #include "components/download/public/common/download_features.h"
50 #include "components/download/public/common/download_file.h"
51 #include "components/download/public/common/download_interrupt_reasons.h"
52 #include "components/download/public/common/download_item_impl_delegate.h"
53 #include "components/download/public/common/download_job_factory.h"
54 #include "components/download/public/common/download_stats.h"
55 #include "components/download/public/common/download_task_runner.h"
56 #include "components/download/public/common/download_ukm_helper.h"
57 #include "components/download/public/common/download_url_parameters.h"
58 #include "components/download/public/common/download_utils.h"
59 #include "net/base/network_change_notifier.h"
60 #include "net/http/http_response_headers.h"
61 #include "net/http/http_status_code.h"
62 #include "net/traffic_annotation/network_traffic_annotation.h"
63 #include "net/url_request/referrer_policy.h"
64 
65 #if defined(OS_ANDROID)
66 #include "components/download/internal/common/android/download_collection_bridge.h"
67 #endif  // defined(OS_ANDROID)
68 
69 namespace download {
70 
71 namespace {
72 
DeleteDownloadedFileDone(base::WeakPtr<DownloadItemImpl> item,base::OnceCallback<void (bool)> callback,bool success)73 void DeleteDownloadedFileDone(base::WeakPtr<DownloadItemImpl> item,
74                               base::OnceCallback<void(bool)> callback,
75                               bool success) {
76   if (success && item.get())
77     item->OnDownloadedFileRemoved();
78   std::move(callback).Run(success);
79 }
80 
81 // Wrapper around DownloadFile::Detach and DownloadFile::Cancel that
82 // takes ownership of the DownloadFile and hence implicitly destroys it
83 // at the end of the function.
DownloadFileDetach(std::unique_ptr<DownloadFile> download_file)84 base::FilePath DownloadFileDetach(std::unique_ptr<DownloadFile> download_file) {
85   DCHECK(GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
86   base::FilePath full_path = download_file->FullPath();
87   download_file->Detach();
88   return full_path;
89 }
90 
MakeCopyOfDownloadFile(DownloadFile * download_file)91 base::FilePath MakeCopyOfDownloadFile(DownloadFile* download_file) {
92   DCHECK(GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
93   base::FilePath temp_file_path;
94   if (!base::CreateTemporaryFile(&temp_file_path))
95     return base::FilePath();
96 
97   if (!base::CopyFile(download_file->FullPath(), temp_file_path)) {
98     DeleteDownloadedFile(temp_file_path);
99     return base::FilePath();
100   }
101 
102   return temp_file_path;
103 }
104 
DownloadFileCancel(std::unique_ptr<DownloadFile> download_file)105 void DownloadFileCancel(std::unique_ptr<DownloadFile> download_file) {
106   DCHECK(GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
107   download_file->Cancel();
108 }
109 
110 // Most of the cancellation pathways behave the same whether the cancellation
111 // was initiated by ther user (CANCELED) or initiated due to browser context
112 // shutdown (SHUTDOWN).
IsCancellation(DownloadInterruptReason reason)113 bool IsCancellation(DownloadInterruptReason reason) {
114   return reason == DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN ||
115          reason == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED;
116 }
117 
GetDownloadCreationTypeNames(DownloadItem::DownloadCreationType type)118 std::string GetDownloadCreationTypeNames(
119     DownloadItem::DownloadCreationType type) {
120   switch (type) {
121     case DownloadItem::TYPE_ACTIVE_DOWNLOAD:
122       return "NEW_DOWNLOAD";
123     case DownloadItem::TYPE_HISTORY_IMPORT:
124       return "HISTORY_IMPORT";
125     case DownloadItem::TYPE_SAVE_PAGE_AS:
126       return "SAVE_PAGE_AS";
127     default:
128       NOTREACHED();
129       return "INVALID_TYPE";
130   }
131 }
132 
GetDownloadDangerNames(DownloadDangerType type)133 std::string GetDownloadDangerNames(DownloadDangerType type) {
134   switch (type) {
135     case DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
136       return "NOT_DANGEROUS";
137     case DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
138       return "DANGEROUS_FILE";
139     case DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
140       return "DANGEROUS_URL";
141     case DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
142       return "DANGEROUS_CONTENT";
143     case DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
144       return "MAYBE_DANGEROUS_CONTENT";
145     case DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
146       return "UNCOMMON_CONTENT";
147     case DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
148       return "USER_VALIDATED";
149     case DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
150       return "DANGEROUS_HOST";
151     case DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
152       return "POTENTIALLY_UNWANTED";
153     case DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY:
154       return "WHITELISTED_BY_POLICY";
155     default:
156       NOTREACHED();
157       return "UNKNOWN_DANGER_TYPE";
158   }
159 }
160 
161 class DownloadItemActivatedData
162     : public base::trace_event::ConvertableToTraceFormat {
163  public:
DownloadItemActivatedData(DownloadItem::DownloadCreationType download_type,uint32_t download_id,std::string original_url,std::string final_url,std::string file_name,DownloadDangerType danger_type,int64_t start_offset,bool has_user_gesture)164   DownloadItemActivatedData(DownloadItem::DownloadCreationType download_type,
165                             uint32_t download_id,
166                             std::string original_url,
167                             std::string final_url,
168                             std::string file_name,
169                             DownloadDangerType danger_type,
170                             int64_t start_offset,
171                             bool has_user_gesture)
172       : download_type_(download_type),
173         download_id_(download_id),
174         original_url_(original_url),
175         final_url_(final_url),
176         file_name_(file_name),
177         danger_type_(danger_type),
178         start_offset_(start_offset),
179         has_user_gesture_(has_user_gesture) {}
180 
181   ~DownloadItemActivatedData() override = default;
182 
AppendAsTraceFormat(std::string * out) const183   void AppendAsTraceFormat(std::string* out) const override {
184     out->append("{");
185     out->append(base::StringPrintf(
186         "\"type\":\"%s\",",
187         GetDownloadCreationTypeNames(download_type_).c_str()));
188     out->append(base::StringPrintf("\"id\":\"%d\",", download_id_));
189     out->append("\"original_url\":");
190     base::EscapeJSONString(original_url_, true, out);
191     out->append(",");
192     out->append("\"final_url\":");
193     base::EscapeJSONString(final_url_, true, out);
194     out->append(",");
195     out->append("\"file_name\":");
196     base::EscapeJSONString(file_name_, true, out);
197     out->append(",");
198     out->append(
199         base::StringPrintf("\"danger_type\":\"%s\",",
200                            GetDownloadDangerNames(danger_type_).c_str()));
201     out->append(
202         base::StringPrintf("\"start_offset\":\"%" PRId64 "\",", start_offset_));
203     out->append(base::StringPrintf("\"has_user_gesture\":\"%s\"",
204                                    has_user_gesture_ ? "true" : "false"));
205     out->append("}");
206   }
207 
208  private:
209   DownloadItem::DownloadCreationType download_type_;
210   uint32_t download_id_;
211   std::string original_url_;
212   std::string final_url_;
213   std::string file_name_;
214   DownloadDangerType danger_type_;
215   int64_t start_offset_;
216   bool has_user_gesture_;
217   DISALLOW_COPY_AND_ASSIGN(DownloadItemActivatedData);
218 };
219 
220 }  // namespace
221 
222 // The maximum number of attempts we will make to resume automatically.
223 const int DownloadItemImpl::kMaxAutoResumeAttempts = 5;
224 
RequestInfo(const std::vector<GURL> & url_chain,const GURL & referrer_url,const GURL & site_url,const GURL & tab_url,const GURL & tab_referrer_url,const base::Optional<url::Origin> & request_initiator,const std::string & suggested_filename,const base::FilePath & forced_file_path,ui::PageTransition transition_type,bool has_user_gesture,const std::string & remote_address,base::Time start_time)225 DownloadItemImpl::RequestInfo::RequestInfo(
226     const std::vector<GURL>& url_chain,
227     const GURL& referrer_url,
228     const GURL& site_url,
229     const GURL& tab_url,
230     const GURL& tab_referrer_url,
231     const base::Optional<url::Origin>& request_initiator,
232     const std::string& suggested_filename,
233     const base::FilePath& forced_file_path,
234     ui::PageTransition transition_type,
235     bool has_user_gesture,
236     const std::string& remote_address,
237     base::Time start_time)
238     : url_chain(url_chain),
239       referrer_url(referrer_url),
240       site_url(site_url),
241       tab_url(tab_url),
242       tab_referrer_url(tab_referrer_url),
243       request_initiator(request_initiator),
244       suggested_filename(suggested_filename),
245       forced_file_path(forced_file_path),
246       transition_type(transition_type),
247       has_user_gesture(has_user_gesture),
248       remote_address(remote_address),
249       start_time(start_time) {}
250 
RequestInfo(const GURL & url)251 DownloadItemImpl::RequestInfo::RequestInfo(const GURL& url)
252     : url_chain(std::vector<GURL>(1, url)), start_time(base::Time::Now()) {}
253 
254 DownloadItemImpl::RequestInfo::RequestInfo() = default;
255 
256 DownloadItemImpl::RequestInfo::RequestInfo(
257     const DownloadItemImpl::RequestInfo& other) = default;
258 
259 DownloadItemImpl::RequestInfo::~RequestInfo() = default;
260 
DestinationInfo(const base::FilePath & target_path,const base::FilePath & current_path,int64_t received_bytes,bool all_data_saved,const std::string & hash,base::Time end_time)261 DownloadItemImpl::DestinationInfo::DestinationInfo(
262     const base::FilePath& target_path,
263     const base::FilePath& current_path,
264     int64_t received_bytes,
265     bool all_data_saved,
266     const std::string& hash,
267     base::Time end_time)
268     : target_path(target_path),
269       current_path(current_path),
270       received_bytes(received_bytes),
271       all_data_saved(all_data_saved),
272       hash(hash),
273       end_time(end_time) {}
274 
DestinationInfo(TargetDisposition target_disposition)275 DownloadItemImpl::DestinationInfo::DestinationInfo(
276     TargetDisposition target_disposition)
277     : target_disposition(target_disposition) {}
278 
279 DownloadItemImpl::DestinationInfo::DestinationInfo() = default;
280 
281 DownloadItemImpl::DestinationInfo::DestinationInfo(
282     const DownloadItemImpl::DestinationInfo& other) = default;
283 
284 DownloadItemImpl::DestinationInfo::~DestinationInfo() = default;
285 
286 // Constructor for reading from the history service.
DownloadItemImpl(DownloadItemImplDelegate * delegate,const std::string & guid,uint32_t download_id,const base::FilePath & current_path,const base::FilePath & target_path,const std::vector<GURL> & url_chain,const GURL & referrer_url,const GURL & site_url,const GURL & tab_url,const GURL & tab_refererr_url,const base::Optional<url::Origin> & request_initiator,const std::string & mime_type,const std::string & original_mime_type,base::Time start_time,base::Time end_time,const std::string & etag,const std::string & last_modified,int64_t received_bytes,int64_t total_bytes,int32_t auto_resume_count,const std::string & hash,DownloadItem::DownloadState state,DownloadDangerType danger_type,DownloadInterruptReason interrupt_reason,bool paused,bool allow_metered,bool opened,base::Time last_access_time,bool transient,const std::vector<DownloadItem::ReceivedSlice> & received_slices,base::Optional<DownloadSchedule> download_schedule,std::unique_ptr<DownloadEntry> download_entry)287 DownloadItemImpl::DownloadItemImpl(
288     DownloadItemImplDelegate* delegate,
289     const std::string& guid,
290     uint32_t download_id,
291     const base::FilePath& current_path,
292     const base::FilePath& target_path,
293     const std::vector<GURL>& url_chain,
294     const GURL& referrer_url,
295     const GURL& site_url,
296     const GURL& tab_url,
297     const GURL& tab_refererr_url,
298     const base::Optional<url::Origin>& request_initiator,
299     const std::string& mime_type,
300     const std::string& original_mime_type,
301     base::Time start_time,
302     base::Time end_time,
303     const std::string& etag,
304     const std::string& last_modified,
305     int64_t received_bytes,
306     int64_t total_bytes,
307     int32_t auto_resume_count,
308     const std::string& hash,
309     DownloadItem::DownloadState state,
310     DownloadDangerType danger_type,
311     DownloadInterruptReason interrupt_reason,
312     bool paused,
313     bool allow_metered,
314     bool opened,
315     base::Time last_access_time,
316     bool transient,
317     const std::vector<DownloadItem::ReceivedSlice>& received_slices,
318     base::Optional<DownloadSchedule> download_schedule,
319     std::unique_ptr<DownloadEntry> download_entry)
320     : request_info_(url_chain,
321                     referrer_url,
322                     site_url,
323                     tab_url,
324                     tab_refererr_url,
325                     request_initiator,
326                     std::string(),
327                     base::FilePath(),
328                     ui::PAGE_TRANSITION_LINK,
329                     false,
330                     std::string(),
331                     start_time),
332       guid_(guid),
333       download_id_(download_id),
334       mime_type_(mime_type),
335       original_mime_type_(original_mime_type),
336       total_bytes_(total_bytes),
337       last_reason_(interrupt_reason),
338       start_tick_(base::TimeTicks()),
339       state_(ExternalToInternalState(state)),
340       danger_type_(danger_type),
341       delegate_(delegate),
342       paused_(paused),
343       allow_metered_(allow_metered),
344       opened_(opened),
345       last_access_time_(last_access_time),
346       transient_(transient),
347       destination_info_(target_path,
348                         current_path,
349                         received_bytes,
350                         state == COMPLETE,
351                         hash,
352                         end_time),
353       auto_resume_count_(auto_resume_count),
354       last_modified_time_(last_modified),
355       etag_(etag),
356       received_slices_(received_slices),
357       is_updating_observers_(false),
358       download_schedule_(std::move(download_schedule)) {
359   delegate_->Attach();
360   DCHECK(state_ == COMPLETE_INTERNAL || state_ == INTERRUPTED_INTERNAL ||
361          state_ == CANCELLED_INTERNAL);
362   DCHECK(base::IsValidGUID(guid_));
363 
364   if (download_entry) {
365     download_source_ = download_entry->download_source;
366     fetch_error_body_ = download_entry->fetch_error_body;
367     request_headers_ = download_entry->request_headers;
368     ukm_download_id_ = download_entry->ukm_download_id;
369     bytes_wasted_ = download_entry->bytes_wasted;
370   } else {
371     ukm_download_id_ = GetUniqueDownloadId();
372   }
373   Init(false /* not actively downloading */, TYPE_HISTORY_IMPORT);
374 }
375 
376 // Constructing for a regular download:
DownloadItemImpl(DownloadItemImplDelegate * delegate,uint32_t download_id,const DownloadCreateInfo & info)377 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
378                                    uint32_t download_id,
379                                    const DownloadCreateInfo& info)
380     : request_info_(info.url_chain,
381                     info.referrer_url,
382                     info.site_url,
383                     info.tab_url,
384                     info.tab_referrer_url,
385                     info.request_initiator,
386                     base::UTF16ToUTF8(info.save_info->suggested_name),
387                     info.save_info->file_path,
388                     info.transition_type ? info.transition_type.value()
389                                          : ui::PAGE_TRANSITION_LINK,
390                     info.has_user_gesture,
391                     info.remote_address,
392                     info.start_time),
393       guid_(info.guid.empty() ? base::GenerateGUID() : info.guid),
394       download_id_(download_id),
395       response_headers_(info.response_headers),
396       content_disposition_(info.content_disposition),
397       mime_type_(info.mime_type),
398       original_mime_type_(info.original_mime_type),
399       total_bytes_(info.total_bytes),
400       last_reason_(info.result),
401       start_tick_(base::TimeTicks::Now()),
402       state_(INITIAL_INTERNAL),
403       delegate_(delegate),
404       is_temporary_(!info.transient && !info.save_info->file_path.empty()),
405       transient_(info.transient),
406       destination_info_(info.save_info->prompt_for_save_location
407                             ? TARGET_DISPOSITION_PROMPT
408                             : TARGET_DISPOSITION_OVERWRITE),
409       last_modified_time_(info.last_modified),
410       etag_(info.etag),
411       is_updating_observers_(false),
412       fetch_error_body_(info.fetch_error_body),
413       request_headers_(info.request_headers),
414       download_source_(info.download_source) {
415   delegate_->Attach();
416   Init(true /* actively downloading */, TYPE_ACTIVE_DOWNLOAD);
417   allow_metered_ |= delegate_->IsActiveNetworkMetered();
418 
419   TRACE_EVENT_INSTANT0("download", "DownloadStarted", TRACE_EVENT_SCOPE_THREAD);
420 }
421 
422 // Constructing for the "Save Page As..." feature:
DownloadItemImpl(DownloadItemImplDelegate * delegate,uint32_t download_id,const base::FilePath & path,const GURL & url,const std::string & mime_type,DownloadJob::CancelRequestCallback cancel_request_callback)423 DownloadItemImpl::DownloadItemImpl(
424     DownloadItemImplDelegate* delegate,
425     uint32_t download_id,
426     const base::FilePath& path,
427     const GURL& url,
428     const std::string& mime_type,
429 
430     DownloadJob::CancelRequestCallback cancel_request_callback)
431     : request_info_(url),
432       guid_(base::GenerateGUID()),
433       download_id_(download_id),
434       mime_type_(mime_type),
435       original_mime_type_(mime_type),
436       start_tick_(base::TimeTicks::Now()),
437       state_(IN_PROGRESS_INTERNAL),
438       delegate_(delegate),
439       destination_info_(path, path, 0, false, std::string(), base::Time()),
440       is_updating_observers_(false) {
441   job_ = DownloadJobFactory::CreateJob(
442       this, std::move(cancel_request_callback), DownloadCreateInfo(), true,
443       URLLoaderFactoryProvider::GetNullPtr(),
444       /*wake_lock_provider_binder*/ base::NullCallback());
445   delegate_->Attach();
446   Init(true /* actively downloading */, TYPE_SAVE_PAGE_AS);
447 }
448 
~DownloadItemImpl()449 DownloadItemImpl::~DownloadItemImpl() {
450   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
451 
452   // Should always have been nuked before now, at worst in
453   // DownloadManager shutdown.
454   DCHECK(!download_file_);
455   CHECK(!is_updating_observers_);
456 
457   for (auto& observer : observers_)
458     observer.OnDownloadDestroyed(this);
459   delegate_->Detach();
460 }
461 
AddObserver(Observer * observer)462 void DownloadItemImpl::AddObserver(Observer* observer) {
463   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
464 
465   observers_.AddObserver(observer);
466 }
467 
RemoveObserver(Observer * observer)468 void DownloadItemImpl::RemoveObserver(Observer* observer) {
469   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
470 
471   observers_.RemoveObserver(observer);
472 }
473 
UpdateObservers()474 void DownloadItemImpl::UpdateObservers() {
475   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
476   DVLOG(20) << __func__ << "()";
477 
478   // Nested updates should not be allowed.
479   DCHECK(!is_updating_observers_);
480 
481   is_updating_observers_ = true;
482   for (auto& observer : observers_)
483     observer.OnDownloadUpdated(this);
484   is_updating_observers_ = false;
485 }
486 
ValidateDangerousDownload()487 void DownloadItemImpl::ValidateDangerousDownload() {
488   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
489   DCHECK(!IsDone());
490   DCHECK(IsDangerous());
491 
492   DVLOG(20) << __func__ << "() download=" << DebugString(true);
493 
494   if (IsDone() || !IsDangerous())
495     return;
496 
497   RecordDangerousDownloadAccept(GetDangerType(), GetTargetFilePath());
498 
499   danger_type_ = DOWNLOAD_DANGER_TYPE_USER_VALIDATED;
500 
501   TRACE_EVENT_INSTANT1("download", "DownloadItemSaftyStateUpdated",
502                        TRACE_EVENT_SCOPE_THREAD, "danger_type",
503                        GetDownloadDangerNames(danger_type_).c_str());
504 
505   UpdateObservers();  // TODO(asanka): This is potentially unsafe. The download
506                       // may not be in a consistent state or around at all after
507                       // invoking observers. http://crbug.com/586610
508 
509   MaybeCompleteDownload();
510 }
511 
ValidateMixedContentDownload()512 void DownloadItemImpl::ValidateMixedContentDownload() {
513   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
514   DCHECK(!IsDone());
515   DCHECK(IsMixedContent());
516 
517   DVLOG(20) << __func__ << "() download=" << DebugString(true);
518 
519   mixed_content_status_ = MixedContentStatus::VALIDATED;
520 
521   UpdateObservers();  // TODO(asanka): This is potentially unsafe. The download
522                       // may not be in a consistent state or around at all after
523                       // invoking observers, but we keep it here because it is
524                       // used in ValidateDangerousDownload(), too.
525                       // http://crbug.com/586610
526 
527   MaybeCompleteDownload();
528 }
529 
StealDangerousDownload(bool delete_file_afterward,AcquireFileCallback callback)530 void DownloadItemImpl::StealDangerousDownload(bool delete_file_afterward,
531                                               AcquireFileCallback callback) {
532   DVLOG(20) << __func__ << "() download = " << DebugString(true);
533   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
534   DCHECK(IsDangerous());
535   DCHECK(AllDataSaved());
536 
537   if (delete_file_afterward) {
538     if (download_file_) {
539       base::PostTaskAndReplyWithResult(
540           GetDownloadTaskRunner().get(), FROM_HERE,
541           base::BindOnce(&DownloadFileDetach, std::move(download_file_)),
542           base::BindOnce(std::move(callback)));
543     } else {
544       std::move(callback).Run(GetFullPath());
545     }
546     destination_info_.current_path.clear();
547     Remove();
548     // Download item has now been deleted.
549   } else if (download_file_) {
550     base::PostTaskAndReplyWithResult(
551         GetDownloadTaskRunner().get(), FROM_HERE,
552         base::BindOnce(&MakeCopyOfDownloadFile, download_file_.get()),
553         base::BindOnce(std::move(callback)));
554   } else {
555     std::move(callback).Run(GetFullPath());
556   }
557 }
558 
Pause()559 void DownloadItemImpl::Pause() {
560   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
561 
562   // Ignore irrelevant states.
563   if (IsPaused())
564     return;
565 
566   switch (state_) {
567     case CANCELLED_INTERNAL:
568     case COMPLETE_INTERNAL:
569     case COMPLETING_INTERNAL:
570       return;
571     case INITIAL_INTERNAL:
572     case INTERRUPTED_INTERNAL:
573     case INTERRUPTED_TARGET_PENDING_INTERNAL:
574     case RESUMING_INTERNAL:
575       // No active request.
576       paused_ = true;
577       UpdateObservers();
578       return;
579 
580     case IN_PROGRESS_INTERNAL:
581     case TARGET_PENDING_INTERNAL:
582       paused_ = true;
583       job_->Pause();
584       UpdateObservers();
585       return;
586 
587     case MAX_DOWNLOAD_INTERNAL_STATE:
588     case TARGET_RESOLVED_INTERNAL:
589       NOTREACHED();
590   }
591 }
592 
Resume(bool user_resume)593 void DownloadItemImpl::Resume(bool user_resume) {
594   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
595   DVLOG(20) << __func__ << "() download = " << DebugString(true);
596   RecordDownloadResumption(GetLastReason(), user_resume);
597 
598   switch (state_) {
599     case CANCELLED_INTERNAL:  // Nothing to resume.
600     case COMPLETE_INTERNAL:
601     case COMPLETING_INTERNAL:
602     case INITIAL_INTERNAL:
603     case INTERRUPTED_TARGET_PENDING_INTERNAL:
604     case RESUMING_INTERNAL:  // Resumption in progress.
605       return;
606 
607     case TARGET_PENDING_INTERNAL:
608     case IN_PROGRESS_INTERNAL:
609       if (!IsPaused())
610         return;
611       paused_ = false;
612       if (job_)
613         job_->Resume(true);
614 
615       UpdateResumptionInfo(true);
616       UpdateObservers();
617       return;
618 
619     case INTERRUPTED_INTERNAL:
620       UpdateResumptionInfo(paused_ || user_resume);
621       paused_ = false;
622       if (auto_resume_count_ >= kMaxAutoResumeAttempts) {
623         RecordAutoResumeCountLimitReached(GetLastReason());
624         UpdateObservers();
625         return;
626       }
627 
628       ResumeInterruptedDownload(user_resume
629                                     ? ResumptionRequestSource::USER
630                                     : ResumptionRequestSource::AUTOMATIC);
631       UpdateObservers();
632       return;
633 
634     case MAX_DOWNLOAD_INTERNAL_STATE:
635     case TARGET_RESOLVED_INTERNAL:
636       NOTREACHED();
637   }
638 }
639 
UpdateResumptionInfo(bool user_resume)640 void DownloadItemImpl::UpdateResumptionInfo(bool user_resume) {
641   if (user_resume) {
642     allow_metered_ |= delegate_->IsActiveNetworkMetered();
643     bytes_wasted_ = 0;
644   }
645 
646   auto_resume_count_ = user_resume ? 0 : ++auto_resume_count_;
647   download_schedule_ = base::nullopt;
648   RecordDownloadLaterEvent(DownloadLaterEvent::kScheduleRemoved);
649 }
650 
Cancel(bool user_cancel)651 void DownloadItemImpl::Cancel(bool user_cancel) {
652   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
653   DVLOG(20) << __func__ << "() download = " << DebugString(true);
654   download_schedule_ = base::nullopt;
655   InterruptAndDiscardPartialState(
656       user_cancel ? DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
657                   : DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN);
658   UpdateObservers();
659 }
660 
Remove()661 void DownloadItemImpl::Remove() {
662   DVLOG(20) << __func__ << "() download = " << DebugString(true);
663   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
664 
665   InterruptAndDiscardPartialState(DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
666   UpdateObservers();
667   NotifyRemoved();
668   delegate_->DownloadRemoved(this);
669   // We have now been deleted.
670 }
671 
OpenDownload()672 void DownloadItemImpl::OpenDownload() {
673   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
674 
675   if (!IsDone()) {
676     // We don't honor the open_when_complete_ flag for temporary
677     // downloads. Don't set it because it shows up in the UI.
678     if (!IsTemporary())
679       open_when_complete_ = !open_when_complete_;
680     return;
681   }
682 
683   if (state_ != COMPLETE_INTERNAL || file_externally_removed_)
684     return;
685 
686   // Ideally, we want to detect errors in opening and report them, but we
687   // don't generally have the proper interface for that to the external
688   // program that opens the file.  So instead we spawn a check to update
689   // the UI if the file has been deleted in parallel with the open.
690   delegate_->CheckForFileRemoval(this);
691   opened_ = true;
692   last_access_time_ = base::Time::Now();
693   for (auto& observer : observers_)
694     observer.OnDownloadOpened(this);
695 
696 #if defined(OS_WIN)
697   // On Windows, don't actually open the file if it has no extension, to prevent
698   // Windows from interpreting it as the command for an executable of the same
699   // name.
700   if (destination_info_.current_path.Extension().empty()) {
701     delegate_->ShowDownloadInShell(this);
702     return;
703   }
704 #endif
705   delegate_->OpenDownload(this);
706 }
707 
ShowDownloadInShell()708 void DownloadItemImpl::ShowDownloadInShell() {
709   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
710 
711   // Ideally, we want to detect errors in showing and report them, but we
712   // don't generally have the proper interface for that to the external
713   // program that opens the file.  So instead we spawn a check to update
714   // the UI if the file has been deleted in parallel with the show.
715   delegate_->CheckForFileRemoval(this);
716   delegate_->ShowDownloadInShell(this);
717 }
718 
RenameDownloadedFileDone(RenameDownloadCallback callback,const base::FilePath & display_name,DownloadRenameResult result)719 void DownloadItemImpl::RenameDownloadedFileDone(
720     RenameDownloadCallback callback,
721     const base::FilePath& display_name,
722     DownloadRenameResult result) {
723   if (result == DownloadRenameResult::SUCCESS) {
724     bool is_content_uri = false;
725 #if defined(OS_ANDROID)
726     is_content_uri = GetFullPath().IsContentUri();
727 #endif  // defined(OS_ANDROID)
728     if (is_content_uri) {
729       SetDisplayName(display_name);
730     } else {
731       auto new_full_path =
732           base::FilePath(GetFullPath().DirName()).Append(display_name);
733       destination_info_.target_path = new_full_path;
734       destination_info_.current_path = new_full_path;
735     }
736     UpdateObservers();
737   }
738   std::move(callback).Run(result);
739 }
740 
Rename(const base::FilePath & display_name,DownloadItem::RenameDownloadCallback callback)741 void DownloadItemImpl::Rename(const base::FilePath& display_name,
742                               DownloadItem::RenameDownloadCallback callback) {
743   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
744 
745   if (display_name.IsAbsolute()) {
746     base::SequencedTaskRunnerHandle::Get()->PostTask(
747         FROM_HERE, base::BindOnce(&DownloadItemImpl::RenameDownloadedFileDone,
748                                   weak_ptr_factory_.GetWeakPtr(),
749                                   std::move(callback), GetFullPath(),
750                                   DownloadRenameResult::FAILURE_NAME_INVALID));
751     return;
752   }
753 
754   base::PostTaskAndReplyWithResult(
755       GetDownloadTaskRunner().get(), FROM_HERE,
756       base::BindOnce(&download::RenameDownloadedFile, GetFullPath(),
757                      display_name),
758       base::BindOnce(&DownloadItemImpl::RenameDownloadedFileDone,
759                      weak_ptr_factory_.GetWeakPtr(), std::move(callback),
760                      display_name));
761 }
762 
GetId() const763 uint32_t DownloadItemImpl::GetId() const {
764   return download_id_;
765 }
766 
GetGuid() const767 const std::string& DownloadItemImpl::GetGuid() const {
768   return guid_;
769 }
770 
GetState() const771 DownloadItem::DownloadState DownloadItemImpl::GetState() const {
772   return InternalToExternalState(state_);
773 }
774 
GetLastReason() const775 DownloadInterruptReason DownloadItemImpl::GetLastReason() const {
776   return last_reason_;
777 }
778 
IsPaused() const779 bool DownloadItemImpl::IsPaused() const {
780   return paused_;
781 }
782 
AllowMetered() const783 bool DownloadItemImpl::AllowMetered() const {
784   return allow_metered_;
785 }
786 
IsTemporary() const787 bool DownloadItemImpl::IsTemporary() const {
788   return is_temporary_;
789 }
790 
CanResume() const791 bool DownloadItemImpl::CanResume() const {
792   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
793   switch (state_) {
794     case INITIAL_INTERNAL:
795     case COMPLETING_INTERNAL:
796     case COMPLETE_INTERNAL:
797     case CANCELLED_INTERNAL:
798     case RESUMING_INTERNAL:
799     case INTERRUPTED_TARGET_PENDING_INTERNAL:
800       return false;
801 
802     case TARGET_PENDING_INTERNAL:
803     case TARGET_RESOLVED_INTERNAL:
804     case IN_PROGRESS_INTERNAL:
805       return IsPaused();
806 
807     case INTERRUPTED_INTERNAL: {
808       ResumeMode resume_mode = GetResumeMode();
809       // Only allow Resume() calls if the resumption mode requires a user
810       // action.
811       return resume_mode == ResumeMode::USER_RESTART ||
812              resume_mode == ResumeMode::USER_CONTINUE;
813     }
814 
815     case MAX_DOWNLOAD_INTERNAL_STATE:
816       NOTREACHED();
817   }
818   return false;
819 }
820 
IsDone() const821 bool DownloadItemImpl::IsDone() const {
822   return IsDownloadDone(GetURL(), GetState(), GetLastReason());
823 }
824 
GetBytesWasted() const825 int64_t DownloadItemImpl::GetBytesWasted() const {
826   return bytes_wasted_;
827 }
828 
GetAutoResumeCount() const829 int32_t DownloadItemImpl::GetAutoResumeCount() const {
830   return auto_resume_count_;
831 }
832 
GetURL() const833 const GURL& DownloadItemImpl::GetURL() const {
834   return request_info_.url_chain.empty() ? GURL::EmptyGURL()
835                                          : request_info_.url_chain.back();
836 }
837 
GetUrlChain() const838 const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const {
839   return request_info_.url_chain;
840 }
841 
GetOriginalUrl() const842 const GURL& DownloadItemImpl::GetOriginalUrl() const {
843   // Be careful about taking the front() of possibly-empty vectors!
844   // http://crbug.com/190096
845   return request_info_.url_chain.empty() ? GURL::EmptyGURL()
846                                          : request_info_.url_chain.front();
847 }
848 
GetReferrerUrl() const849 const GURL& DownloadItemImpl::GetReferrerUrl() const {
850   return request_info_.referrer_url;
851 }
852 
GetSiteUrl() const853 const GURL& DownloadItemImpl::GetSiteUrl() const {
854   return request_info_.site_url;
855 }
856 
GetTabUrl() const857 const GURL& DownloadItemImpl::GetTabUrl() const {
858   return request_info_.tab_url;
859 }
860 
GetTabReferrerUrl() const861 const GURL& DownloadItemImpl::GetTabReferrerUrl() const {
862   return request_info_.tab_referrer_url;
863 }
864 
GetRequestInitiator() const865 const base::Optional<url::Origin>& DownloadItemImpl::GetRequestInitiator()
866     const {
867   return request_info_.request_initiator;
868 }
869 
GetSuggestedFilename() const870 std::string DownloadItemImpl::GetSuggestedFilename() const {
871   return request_info_.suggested_filename;
872 }
873 
874 const scoped_refptr<const net::HttpResponseHeaders>&
GetResponseHeaders() const875 DownloadItemImpl::GetResponseHeaders() const {
876   return response_headers_;
877 }
878 
GetContentDisposition() const879 std::string DownloadItemImpl::GetContentDisposition() const {
880   return content_disposition_;
881 }
882 
GetMimeType() const883 std::string DownloadItemImpl::GetMimeType() const {
884   return mime_type_;
885 }
886 
GetOriginalMimeType() const887 std::string DownloadItemImpl::GetOriginalMimeType() const {
888   return original_mime_type_;
889 }
890 
GetRemoteAddress() const891 std::string DownloadItemImpl::GetRemoteAddress() const {
892   return request_info_.remote_address;
893 }
894 
HasUserGesture() const895 bool DownloadItemImpl::HasUserGesture() const {
896   return request_info_.has_user_gesture;
897 }
898 
GetTransitionType() const899 ui::PageTransition DownloadItemImpl::GetTransitionType() const {
900   return request_info_.transition_type;
901 }
902 
GetLastModifiedTime() const903 const std::string& DownloadItemImpl::GetLastModifiedTime() const {
904   return last_modified_time_;
905 }
906 
GetETag() const907 const std::string& DownloadItemImpl::GetETag() const {
908   return etag_;
909 }
910 
IsSavePackageDownload() const911 bool DownloadItemImpl::IsSavePackageDownload() const {
912   return job_ && job_->IsSavePackageDownload();
913 }
914 
GetDownloadSource() const915 DownloadSource DownloadItemImpl::GetDownloadSource() const {
916   return download_source_;
917 }
918 
GetFullPath() const919 const base::FilePath& DownloadItemImpl::GetFullPath() const {
920   return destination_info_.current_path;
921 }
922 
GetTargetFilePath() const923 const base::FilePath& DownloadItemImpl::GetTargetFilePath() const {
924   return destination_info_.target_path;
925 }
926 
GetForcedFilePath() const927 const base::FilePath& DownloadItemImpl::GetForcedFilePath() const {
928   // TODO(asanka): Get rid of GetForcedFilePath(). We should instead just
929   // require that clients respect GetTargetFilePath() if it is already set.
930   return request_info_.forced_file_path;
931 }
932 
GetTemporaryFilePath() const933 base::FilePath DownloadItemImpl::GetTemporaryFilePath() const {
934   if (state_ == TARGET_PENDING_INTERNAL ||
935       state_ == INTERRUPTED_TARGET_PENDING_INTERNAL)
936     return download_file_ ? download_file_->FullPath() : base::FilePath();
937   return base::FilePath();
938 }
939 
GetFileNameToReportUser() const940 base::FilePath DownloadItemImpl::GetFileNameToReportUser() const {
941   if (!display_name_.empty())
942     return display_name_;
943   return GetTargetFilePath().BaseName();
944 }
945 
GetTargetDisposition() const946 DownloadItem::TargetDisposition DownloadItemImpl::GetTargetDisposition() const {
947   return destination_info_.target_disposition;
948 }
949 
GetHash() const950 const std::string& DownloadItemImpl::GetHash() const {
951   return destination_info_.hash;
952 }
953 
GetFileExternallyRemoved() const954 bool DownloadItemImpl::GetFileExternallyRemoved() const {
955   return file_externally_removed_;
956 }
957 
DeleteFile(base::OnceCallback<void (bool)> callback)958 void DownloadItemImpl::DeleteFile(base::OnceCallback<void(bool)> callback) {
959   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
960   if (GetState() != DownloadItem::COMPLETE) {
961     // Pass a null WeakPtr so it doesn't call OnDownloadedFileRemoved.
962     base::SequencedTaskRunnerHandle::Get()->PostTask(
963         FROM_HERE, base::BindOnce(&DeleteDownloadedFileDone,
964                                   base::WeakPtr<DownloadItemImpl>(),
965                                   std::move(callback), false));
966     return;
967   }
968   if (GetFullPath().empty() || file_externally_removed_) {
969     // Pass a null WeakPtr so it doesn't call OnDownloadedFileRemoved.
970     base::SequencedTaskRunnerHandle::Get()->PostTask(
971         FROM_HERE, base::BindOnce(&DeleteDownloadedFileDone,
972                                   base::WeakPtr<DownloadItemImpl>(),
973                                   std::move(callback), true));
974     return;
975   }
976   base::PostTaskAndReplyWithResult(
977       GetDownloadTaskRunner().get(), FROM_HERE,
978       base::BindOnce(&DeleteDownloadedFile, GetFullPath()),
979       base::BindOnce(&DeleteDownloadedFileDone, weak_ptr_factory_.GetWeakPtr(),
980                      std::move(callback)));
981 }
982 
GetDownloadFile()983 DownloadFile* DownloadItemImpl::GetDownloadFile() {
984   return download_file_.get();
985 }
986 
IsDangerous() const987 bool DownloadItemImpl::IsDangerous() const {
988   return danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
989          danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
990          danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
991          danger_type_ == DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
992          danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
993          danger_type_ == DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED ||
994          danger_type_ == DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED ||
995          danger_type_ == DOWNLOAD_DANGER_TYPE_BLOCKED_TOO_LARGE ||
996          danger_type_ == DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING ||
997          danger_type_ == DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_BLOCK ||
998          danger_type_ == DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING;
999 }
1000 
IsMixedContent() const1001 bool DownloadItemImpl::IsMixedContent() const {
1002   return mixed_content_status_ == MixedContentStatus::WARN ||
1003          mixed_content_status_ == MixedContentStatus::BLOCK ||
1004          mixed_content_status_ == MixedContentStatus::SILENT_BLOCK;
1005 }
1006 
GetDangerType() const1007 DownloadDangerType DownloadItemImpl::GetDangerType() const {
1008   return danger_type_;
1009 }
1010 
GetMixedContentStatus() const1011 DownloadItem::MixedContentStatus DownloadItemImpl::GetMixedContentStatus()
1012     const {
1013   return mixed_content_status_;
1014 }
1015 
TimeRemaining(base::TimeDelta * remaining) const1016 bool DownloadItemImpl::TimeRemaining(base::TimeDelta* remaining) const {
1017   if (total_bytes_ <= 0)
1018     return false;  // We never received the content_length for this download.
1019 
1020   int64_t speed = CurrentSpeed();
1021   if (speed == 0)
1022     return false;
1023 
1024   *remaining =
1025       base::TimeDelta::FromSeconds((total_bytes_ - GetReceivedBytes()) / speed);
1026   return true;
1027 }
1028 
CurrentSpeed() const1029 int64_t DownloadItemImpl::CurrentSpeed() const {
1030   if (IsPaused())
1031     return 0;
1032   return bytes_per_sec_;
1033 }
1034 
PercentComplete() const1035 int DownloadItemImpl::PercentComplete() const {
1036   // If the delegate is delaying completion of the download, then we have no
1037   // idea how long it will take.
1038   if (delegate_delayed_complete_ || total_bytes_ <= 0)
1039     return -1;
1040 
1041   return static_cast<int>(GetReceivedBytes() * 100.0 / total_bytes_);
1042 }
1043 
AllDataSaved() const1044 bool DownloadItemImpl::AllDataSaved() const {
1045   return destination_info_.all_data_saved;
1046 }
1047 
GetTotalBytes() const1048 int64_t DownloadItemImpl::GetTotalBytes() const {
1049   return total_bytes_;
1050 }
1051 
GetReceivedBytes() const1052 int64_t DownloadItemImpl::GetReceivedBytes() const {
1053   return destination_info_.received_bytes;
1054 }
1055 
1056 const std::vector<DownloadItem::ReceivedSlice>&
GetReceivedSlices() const1057 DownloadItemImpl::GetReceivedSlices() const {
1058   return received_slices_;
1059 }
1060 
GetStartTime() const1061 base::Time DownloadItemImpl::GetStartTime() const {
1062   return request_info_.start_time;
1063 }
1064 
GetEndTime() const1065 base::Time DownloadItemImpl::GetEndTime() const {
1066   return destination_info_.end_time;
1067 }
1068 
CanShowInFolder()1069 bool DownloadItemImpl::CanShowInFolder() {
1070   // A download can be shown in the folder if the downloaded file is in a known
1071   // location.
1072   return CanOpenDownload() && !GetFullPath().empty();
1073 }
1074 
CanOpenDownload()1075 bool DownloadItemImpl::CanOpenDownload() {
1076   // We can open the file or mark it for opening on completion if the download
1077   // is expected to complete successfully. Exclude temporary downloads, since
1078   // they aren't owned by the download system.
1079   const bool is_complete = GetState() == DownloadItem::COMPLETE;
1080   return (!IsDone() || is_complete) && !IsTemporary() &&
1081          !file_externally_removed_;
1082 }
1083 
ShouldOpenFileBasedOnExtension()1084 bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() {
1085   return delegate_->ShouldAutomaticallyOpenFile(GetURL(), GetTargetFilePath());
1086 }
1087 
ShouldOpenFileByPolicyBasedOnExtension()1088 bool DownloadItemImpl::ShouldOpenFileByPolicyBasedOnExtension() {
1089   return delegate_->ShouldAutomaticallyOpenFileByPolicy(GetURL(),
1090                                                         GetTargetFilePath());
1091 }
1092 
GetOpenWhenComplete() const1093 bool DownloadItemImpl::GetOpenWhenComplete() const {
1094   return open_when_complete_;
1095 }
1096 
GetAutoOpened()1097 bool DownloadItemImpl::GetAutoOpened() {
1098   return auto_opened_;
1099 }
1100 
GetOpened() const1101 bool DownloadItemImpl::GetOpened() const {
1102   return opened_;
1103 }
1104 
GetLastAccessTime() const1105 base::Time DownloadItemImpl::GetLastAccessTime() const {
1106   return last_access_time_;
1107 }
1108 
IsTransient() const1109 bool DownloadItemImpl::IsTransient() const {
1110   return transient_;
1111 }
1112 
IsParallelDownload() const1113 bool DownloadItemImpl::IsParallelDownload() const {
1114   bool is_parallelizable = job_ ? job_->IsParallelizable() : false;
1115   return is_parallelizable && download::IsParallelDownloadEnabled();
1116 }
1117 
GetDownloadCreationType() const1118 DownloadItem::DownloadCreationType DownloadItemImpl::GetDownloadCreationType()
1119     const {
1120   return download_type_;
1121 }
1122 
GetDownloadSchedule() const1123 const base::Optional<DownloadSchedule>& DownloadItemImpl::GetDownloadSchedule()
1124     const {
1125   return download_schedule_;
1126 }
1127 
OnContentCheckCompleted(DownloadDangerType danger_type,DownloadInterruptReason reason)1128 void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type,
1129                                                DownloadInterruptReason reason) {
1130   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1131   DCHECK(AllDataSaved());
1132 
1133   // Danger type is only allowed to be set on an active download after all data
1134   // has been saved. This excludes all other states. In particular,
1135   // OnContentCheckCompleted() isn't allowed on an INTERRUPTED download since
1136   // such an interruption would need to happen between OnAllDataSaved() and
1137   // OnContentCheckCompleted() during which no disk or network activity
1138   // should've taken place.
1139   DCHECK_EQ(state_, IN_PROGRESS_INTERNAL);
1140   DVLOG(20) << __func__ << "() danger_type=" << danger_type
1141             << " download=" << DebugString(true);
1142   SetDangerType(danger_type);
1143   if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
1144     InterruptAndDiscardPartialState(reason);
1145     DCHECK_EQ(ResumeMode::INVALID, GetResumeMode());
1146   }
1147   UpdateObservers();
1148 }
1149 
OnAsyncScanningCompleted(DownloadDangerType danger_type)1150 void DownloadItemImpl::OnAsyncScanningCompleted(
1151     DownloadDangerType danger_type) {
1152   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1153   DCHECK(AllDataSaved());
1154 
1155   DVLOG(20) << __func__ << "() danger_type=" << danger_type
1156             << " download=" << DebugString(true);
1157   SetDangerType(danger_type);
1158   UpdateObservers();
1159 }
1160 
OnDownloadScheduleChanged(base::Optional<DownloadSchedule> schedule)1161 void DownloadItemImpl::OnDownloadScheduleChanged(
1162     base::Optional<DownloadSchedule> schedule) {
1163   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1164   if (!base::FeatureList::IsEnabled(features::kDownloadLater) ||
1165       state_ != INTERRUPTED_INTERNAL) {
1166     return;
1167   }
1168 
1169   RecordDownloadLaterEvent(DownloadLaterEvent::kScheduleChanged);
1170 
1171   SwapDownloadSchedule(std::move(schedule));
1172 
1173   // Need to start later, don't proceed and ping observers.
1174   if (ShouldDownloadLater()) {
1175     UpdateObservers();
1176     return;
1177   }
1178 
1179   // Download now. allow_metered_ will be updated afterward.
1180   Resume(true /*user_resume*/);
1181 }
1182 
SetOpenWhenComplete(bool open)1183 void DownloadItemImpl::SetOpenWhenComplete(bool open) {
1184   open_when_complete_ = open;
1185 }
1186 
SetOpened(bool opened)1187 void DownloadItemImpl::SetOpened(bool opened) {
1188   opened_ = opened;
1189 }
1190 
SetLastAccessTime(base::Time last_access_time)1191 void DownloadItemImpl::SetLastAccessTime(base::Time last_access_time) {
1192   last_access_time_ = last_access_time;
1193   UpdateObservers();
1194 }
1195 
SetDisplayName(const base::FilePath & name)1196 void DownloadItemImpl::SetDisplayName(const base::FilePath& name) {
1197   display_name_ = name;
1198 }
1199 
DebugString(bool verbose) const1200 std::string DownloadItemImpl::DebugString(bool verbose) const {
1201   std::string description = base::StringPrintf(
1202       "{ id = %d"
1203       " state = %s",
1204       download_id_, DebugDownloadStateString(state_));
1205 
1206   // Construct a string of the URL chain.
1207   std::string url_list("<none>");
1208   if (!request_info_.url_chain.empty()) {
1209     auto iter = request_info_.url_chain.begin();
1210     auto last = request_info_.url_chain.end();
1211     url_list = (*iter).is_valid() ? (*iter).spec() : "<invalid>";
1212     ++iter;
1213     for (; verbose && (iter != last); ++iter) {
1214       url_list += " ->\n\t";
1215       const GURL& next_url = *iter;
1216       url_list += next_url.is_valid() ? next_url.spec() : "<invalid>";
1217     }
1218   }
1219 
1220   if (verbose) {
1221     description += base::StringPrintf(
1222         " total = %" PRId64 " received = %" PRId64
1223         " reason = %s"
1224         " paused = %c"
1225         " resume_mode = %s"
1226         " auto_resume_count = %d"
1227         " danger = %d"
1228         " all_data_saved = %c"
1229         " last_modified = '%s'"
1230         " etag = '%s'"
1231         " has_download_file = %s"
1232         " url_chain = \n\t\"%s\"\n\t"
1233         " current_path = \"%" PRFilePath
1234         "\"\n\t"
1235         " target_path = \"%" PRFilePath
1236         "\""
1237         " referrer = \"%s\""
1238         " site_url = \"%s\"",
1239         GetTotalBytes(), GetReceivedBytes(),
1240         DownloadInterruptReasonToString(last_reason_).c_str(),
1241         IsPaused() ? 'T' : 'F', DebugResumeModeString(GetResumeMode()),
1242         auto_resume_count_, GetDangerType(), AllDataSaved() ? 'T' : 'F',
1243         GetLastModifiedTime().c_str(), GetETag().c_str(),
1244         download_file_ ? "true" : "false", url_list.c_str(),
1245         GetFullPath().value().c_str(), GetTargetFilePath().value().c_str(),
1246         GetReferrerUrl().spec().c_str(), GetSiteUrl().spec().c_str());
1247   } else {
1248     description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
1249   }
1250 
1251   description += " }";
1252 
1253   return description;
1254 }
1255 
SimulateErrorForTesting(DownloadInterruptReason reason)1256 void DownloadItemImpl::SimulateErrorForTesting(DownloadInterruptReason reason) {
1257   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1258 
1259   InterruptWithPartialState(GetReceivedBytes(), nullptr, reason);
1260   UpdateObservers();
1261 }
1262 
GetResumeMode() const1263 ResumeMode DownloadItemImpl::GetResumeMode() const {
1264   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1265 
1266   // We can't continue without a handle on the intermediate file.
1267   // We also can't continue if we don't have some verifier to make sure
1268   // we're getting the same file.
1269   bool restart_required =
1270       (GetFullPath().empty() ||
1271        (!HasStrongValidators() &&
1272         !base::FeatureList::IsEnabled(
1273             features::kAllowDownloadResumptionWithoutStrongValidators)));
1274   // We won't auto-restart if we've used up our attempts or the
1275   // download has been paused by user action.
1276   bool user_action_required =
1277       (auto_resume_count_ >= kMaxAutoResumeAttempts || IsPaused());
1278 
1279   return GetDownloadResumeMode(GetURL(), last_reason_, restart_required,
1280                                user_action_required);
1281 }
1282 
HasStrongValidators() const1283 bool DownloadItemImpl::HasStrongValidators() const {
1284   return !etag_.empty() || !last_modified_time_.empty();
1285 }
1286 
BindWakeLockProvider(mojo::PendingReceiver<device::mojom::WakeLockProvider> receiver)1287 void DownloadItemImpl::BindWakeLockProvider(
1288     mojo::PendingReceiver<device::mojom::WakeLockProvider> receiver) {
1289   if (delegate_)
1290     delegate_->BindWakeLockProvider(std::move(receiver));
1291 }
1292 
UpdateValidatorsOnResumption(const DownloadCreateInfo & new_create_info)1293 void DownloadItemImpl::UpdateValidatorsOnResumption(
1294     const DownloadCreateInfo& new_create_info) {
1295   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1296   DCHECK_EQ(RESUMING_INTERNAL, state_);
1297   DCHECK(!new_create_info.url_chain.empty());
1298 
1299   // We are going to tack on any new redirects to our list of redirects.
1300   // When a download is resumed, the URL used for the resumption request is the
1301   // one at the end of the previous redirect chain. Tacking additional redirects
1302   // to the end of this chain ensures that:
1303   // - If the download needs to be resumed again, the ETag/Last-Modified headers
1304   //   will be used with the last server that sent them to us.
1305   // - The redirect chain contains all the servers that were involved in this
1306   //   download since the initial request, in order.
1307   auto chain_iter = new_create_info.url_chain.begin();
1308   if (*chain_iter == request_info_.url_chain.back())
1309     ++chain_iter;
1310 
1311   // Record some stats. If the precondition failed (the server returned
1312   // HTTP_PRECONDITION_FAILED), then the download will automatically retried as
1313   // a full request rather than a partial. Full restarts clobber validators.
1314   if (etag_ != new_create_info.etag ||
1315       last_modified_time_ != new_create_info.last_modified) {
1316     received_slices_.clear();
1317     destination_info_.received_bytes = 0;
1318   }
1319 
1320   request_info_.url_chain.insert(request_info_.url_chain.end(), chain_iter,
1321                                  new_create_info.url_chain.end());
1322   etag_ = new_create_info.etag;
1323   last_modified_time_ = new_create_info.last_modified;
1324   response_headers_ = new_create_info.response_headers;
1325   content_disposition_ = new_create_info.content_disposition;
1326   // It is possible that the previous download attempt failed right before the
1327   // response is received. Need to reset the MIME type.
1328   mime_type_ = new_create_info.mime_type;
1329 
1330   // Don't update observers. This method is expected to be called just before a
1331   // DownloadFile is created and Start() is called. The observers will be
1332   // notified when the download transitions to the IN_PROGRESS state.
1333 }
1334 
NotifyRemoved()1335 void DownloadItemImpl::NotifyRemoved() {
1336   for (auto& observer : observers_)
1337     observer.OnDownloadRemoved(this);
1338 }
1339 
OnDownloadedFileRemoved()1340 void DownloadItemImpl::OnDownloadedFileRemoved() {
1341   file_externally_removed_ = true;
1342   DVLOG(20) << __func__ << "() download=" << DebugString(true);
1343   UpdateObservers();
1344 }
1345 
1346 base::WeakPtr<DownloadDestinationObserver>
DestinationObserverAsWeakPtr()1347 DownloadItemImpl::DestinationObserverAsWeakPtr() {
1348   return weak_ptr_factory_.GetWeakPtr();
1349 }
1350 
SetTotalBytes(int64_t total_bytes)1351 void DownloadItemImpl::SetTotalBytes(int64_t total_bytes) {
1352   total_bytes_ = total_bytes;
1353 }
1354 
OnAllDataSaved(int64_t total_bytes,std::unique_ptr<crypto::SecureHash> hash_state)1355 void DownloadItemImpl::OnAllDataSaved(
1356     int64_t total_bytes,
1357     std::unique_ptr<crypto::SecureHash> hash_state) {
1358   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1359   DCHECK(!AllDataSaved());
1360   destination_info_.all_data_saved = true;
1361   SetTotalBytes(total_bytes);
1362   UpdateProgress(total_bytes, 0);
1363   received_slices_.clear();
1364   SetHashState(std::move(hash_state));
1365   hash_state_.reset();  // No need to retain hash_state_ since we are done with
1366                         // the download and don't expect to receive any more
1367                         // data.
1368 
1369   if (received_bytes_at_length_mismatch_ > 0) {
1370     if (total_bytes > received_bytes_at_length_mismatch_) {
1371       RecordDownloadCountWithSource(
1372           MORE_BYTES_RECEIVED_AFTER_CONTENT_LENGTH_MISMATCH_COUNT,
1373           download_source_);
1374     } else if (total_bytes == received_bytes_at_length_mismatch_) {
1375       RecordDownloadCountWithSource(
1376           NO_BYTES_RECEIVED_AFTER_CONTENT_LENGTH_MISMATCH_COUNT,
1377           download_source_);
1378     } else {
1379       // This could happen if the content changes on the server.
1380     }
1381   }
1382   DVLOG(20) << __func__ << "() download=" << DebugString(true);
1383   UpdateObservers();
1384 }
1385 
MarkAsComplete()1386 void DownloadItemImpl::MarkAsComplete() {
1387   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1388 
1389   DCHECK(AllDataSaved());
1390   destination_info_.end_time = base::Time::Now();
1391   TransitionTo(COMPLETE_INTERNAL);
1392   UpdateObservers();
1393 }
1394 
DestinationUpdate(int64_t bytes_so_far,int64_t bytes_per_sec,const std::vector<DownloadItem::ReceivedSlice> & received_slices)1395 void DownloadItemImpl::DestinationUpdate(
1396     int64_t bytes_so_far,
1397     int64_t bytes_per_sec,
1398     const std::vector<DownloadItem::ReceivedSlice>& received_slices) {
1399   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1400   // If the download is in any other state we don't expect any
1401   // DownloadDestinationObserver callbacks. An interruption or a cancellation
1402   // results in a call to ReleaseDownloadFile which invalidates the weak
1403   // reference held by the DownloadFile and hence cuts off any pending
1404   // callbacks.
1405   DCHECK(state_ == TARGET_PENDING_INTERNAL || state_ == IN_PROGRESS_INTERNAL ||
1406          state_ == INTERRUPTED_TARGET_PENDING_INTERNAL);
1407 
1408   // There must be no pending deferred_interrupt_reason_.
1409   DCHECK(deferred_interrupt_reason_ == DOWNLOAD_INTERRUPT_REASON_NONE ||
1410          state_ == INTERRUPTED_TARGET_PENDING_INTERNAL);
1411 
1412   DVLOG(20) << __func__ << "() so_far=" << bytes_so_far
1413             << " per_sec=" << bytes_per_sec
1414             << " download=" << DebugString(true);
1415 
1416   UpdateProgress(bytes_so_far, bytes_per_sec);
1417   received_slices_ = received_slices;
1418   TRACE_EVENT_INSTANT1("download", "DownloadItemUpdated",
1419                        TRACE_EVENT_SCOPE_THREAD, "bytes_so_far",
1420                        GetReceivedBytes());
1421 
1422   if (IsPaused() && destination_info_.received_bytes == bytes_so_far)
1423     return;
1424 
1425   UpdateObservers();
1426 }
1427 
DestinationError(DownloadInterruptReason reason,int64_t bytes_so_far,std::unique_ptr<crypto::SecureHash> secure_hash)1428 void DownloadItemImpl::DestinationError(
1429     DownloadInterruptReason reason,
1430     int64_t bytes_so_far,
1431     std::unique_ptr<crypto::SecureHash> secure_hash) {
1432   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1433   // If the download is in any other state we don't expect any
1434   // DownloadDestinationObserver callbacks. An interruption or a cancellation
1435   // results in a call to ReleaseDownloadFile which invalidates the weak
1436   // reference held by the DownloadFile and hence cuts off any pending
1437   // callbacks.
1438   DCHECK(state_ == TARGET_PENDING_INTERNAL || state_ == IN_PROGRESS_INTERNAL);
1439   DVLOG(20) << __func__
1440             << "() reason:" << DownloadInterruptReasonToString(reason)
1441             << " this:" << DebugString(true);
1442 
1443   InterruptWithPartialState(bytes_so_far, std::move(secure_hash), reason);
1444   UpdateObservers();
1445 }
1446 
DestinationCompleted(int64_t total_bytes,std::unique_ptr<crypto::SecureHash> secure_hash)1447 void DownloadItemImpl::DestinationCompleted(
1448     int64_t total_bytes,
1449     std::unique_ptr<crypto::SecureHash> secure_hash) {
1450   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1451   // If the download is in any other state we don't expect any
1452   // DownloadDestinationObserver callbacks. An interruption or a cancellation
1453   // results in a call to ReleaseDownloadFile which invalidates the weak
1454   // reference held by the DownloadFile and hence cuts off any pending
1455   // callbacks.
1456   DCHECK(state_ == TARGET_PENDING_INTERNAL || state_ == IN_PROGRESS_INTERNAL ||
1457          state_ == INTERRUPTED_TARGET_PENDING_INTERNAL);
1458   DVLOG(20) << __func__ << "() download=" << DebugString(true);
1459 
1460   OnAllDataSaved(total_bytes, std::move(secure_hash));
1461   MaybeCompleteDownload();
1462 }
1463 
SetDelegate(DownloadItemImplDelegate * delegate)1464 void DownloadItemImpl::SetDelegate(DownloadItemImplDelegate* delegate) {
1465   delegate_->Detach();
1466   delegate_ = delegate;
1467   delegate_->Attach();
1468 }
1469 
SetDownloadId(uint32_t download_id)1470 void DownloadItemImpl::SetDownloadId(uint32_t download_id) {
1471   download_id_ = download_id;
1472 }
1473 
SetAutoResumeCountForTesting(int32_t auto_resume_count)1474 void DownloadItemImpl::SetAutoResumeCountForTesting(int32_t auto_resume_count) {
1475   auto_resume_count_ = auto_resume_count;
1476 }
1477 
1478 // **** Download progression cascade
1479 
Init(bool active,DownloadItem::DownloadCreationType download_type)1480 void DownloadItemImpl::Init(bool active,
1481                             DownloadItem::DownloadCreationType download_type) {
1482   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1483 
1484   download_type_ = download_type;
1485   std::string file_name;
1486   if (download_type == TYPE_HISTORY_IMPORT) {
1487     // target_path_ works for History and Save As versions.
1488     file_name = GetTargetFilePath().AsUTF8Unsafe();
1489   } else {
1490     // See if it's set programmatically.
1491     file_name = GetForcedFilePath().AsUTF8Unsafe();
1492     // Possibly has a 'download' attribute for the anchor.
1493     if (file_name.empty())
1494       file_name = GetSuggestedFilename();
1495     // From the URL file name.
1496     if (file_name.empty())
1497       file_name = GetURL().ExtractFileName();
1498   }
1499 
1500   auto active_data = std::make_unique<DownloadItemActivatedData>(
1501       download_type, GetId(), GetOriginalUrl().spec(), GetURL().spec(),
1502       file_name, GetDangerType(), GetReceivedBytes(), HasUserGesture());
1503 
1504   if (active) {
1505     TRACE_EVENT_ASYNC_BEGIN1("download", "DownloadItemActive", download_id_,
1506                              "download_item", std::move(active_data));
1507     ukm_download_id_ = GetUniqueDownloadId();
1508   } else {
1509     TRACE_EVENT_INSTANT1("download", "DownloadItemActive",
1510                          TRACE_EVENT_SCOPE_THREAD, "download_item",
1511                          std::move(active_data));
1512   }
1513 
1514   DVLOG(20) << __func__ << "() " << DebugString(true);
1515 }
1516 
1517 // We're starting the download.
Start(std::unique_ptr<DownloadFile> file,DownloadJob::CancelRequestCallback cancel_request_callback,const DownloadCreateInfo & new_create_info,URLLoaderFactoryProvider::URLLoaderFactoryProviderPtr url_loader_factory_provider)1518 void DownloadItemImpl::Start(
1519     std::unique_ptr<DownloadFile> file,
1520     DownloadJob::CancelRequestCallback cancel_request_callback,
1521     const DownloadCreateInfo& new_create_info,
1522     URLLoaderFactoryProvider::URLLoaderFactoryProviderPtr
1523         url_loader_factory_provider) {
1524   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1525   CHECK(!download_file_) << "last interrupt reason: "
1526                          << DownloadInterruptReasonToString(last_reason_)
1527                          << ", state: " << DebugDownloadStateString(state_);
1528   DVLOG(20) << __func__ << "() this=" << DebugString(true);
1529   RecordDownloadCountWithSource(START_COUNT, download_source_);
1530 
1531   download_file_ = std::move(file);
1532   job_ = DownloadJobFactory::CreateJob(
1533       this, std::move(cancel_request_callback), new_create_info, false,
1534       std::move(url_loader_factory_provider),
1535       base::BindRepeating(&DownloadItemImpl::BindWakeLockProvider,
1536                           weak_ptr_factory_.GetWeakPtr()));
1537   if (job_->IsParallelizable()) {
1538     RecordParallelizableDownloadCount(START_COUNT, IsParallelDownloadEnabled());
1539   }
1540 
1541   deferred_interrupt_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE;
1542 
1543   if (state_ == CANCELLED_INTERNAL) {
1544     // The download was in the process of resuming when it was cancelled. Don't
1545     // proceed.
1546     ReleaseDownloadFile(true);
1547     job_->Cancel(true);
1548     return;
1549   }
1550 
1551   // The state could be one of the following:
1552   //
1553   // INITIAL_INTERNAL: A normal download attempt.
1554   //
1555   // RESUMING_INTERNAL: A resumption attempt. May or may not have been
1556   //     successful.
1557   DCHECK(state_ == INITIAL_INTERNAL || state_ == RESUMING_INTERNAL);
1558 
1559   // If the state_ is INITIAL_INTERNAL, then the target path must be empty.
1560   DCHECK(state_ != INITIAL_INTERNAL || GetTargetFilePath().empty());
1561 
1562   // If a resumption attempted failed, or if the download was DOA, then the
1563   // download should go back to being interrupted.
1564   if (new_create_info.result != DOWNLOAD_INTERRUPT_REASON_NONE) {
1565     DCHECK(!download_file_);
1566 
1567     // Download requests that are interrupted by Start() should result in a
1568     // DownloadCreateInfo with an intact DownloadSaveInfo.
1569     DCHECK(new_create_info.save_info);
1570 
1571     std::unique_ptr<crypto::SecureHash> hash_state =
1572         new_create_info.save_info->hash_state
1573             ? new_create_info.save_info->hash_state->Clone()
1574             : nullptr;
1575 
1576     hash_state_ = std::move(hash_state);
1577     destination_info_.hash.clear();
1578     deferred_interrupt_reason_ = new_create_info.result;
1579     TransitionTo(INTERRUPTED_TARGET_PENDING_INTERNAL);
1580     DetermineDownloadTarget();
1581     return;
1582   }
1583 
1584   if (state_ == INITIAL_INTERNAL) {
1585     RecordNewDownloadStarted(net::NetworkChangeNotifier::GetConnectionType(),
1586                              download_source_);
1587     if (job_->IsParallelizable()) {
1588       RecordParallelizableDownloadCount(NEW_DOWNLOAD_COUNT,
1589                                         IsParallelDownloadEnabled());
1590     }
1591     RecordDownloadMimeType(mime_type_);
1592     DownloadContent file_type = DownloadContentFromMimeType(mime_type_, false);
1593     bool is_same_host_download = base::EndsWith(
1594         new_create_info.url().host(), new_create_info.site_url.host());
1595     DownloadConnectionSecurity state = CheckDownloadConnectionSecurity(
1596         new_create_info.url(), new_create_info.url_chain);
1597     DownloadUkmHelper::RecordDownloadStarted(
1598         ukm_download_id_, new_create_info.ukm_source_id, file_type,
1599         download_source_, state, is_same_host_download);
1600     RecordDownloadValidationMetrics(DownloadMetricsCallsite::kDownloadItem,
1601                                     state, file_type);
1602 
1603     if (!delegate_->IsOffTheRecord()) {
1604       RecordDownloadCountWithSource(NEW_DOWNLOAD_COUNT_NORMAL_PROFILE,
1605                                     download_source_);
1606       RecordDownloadMimeTypeForNormalProfile(mime_type_);
1607     }
1608   }
1609 
1610   // Successful download start.
1611   DCHECK(download_file_);
1612   DCHECK(job_);
1613 
1614   if (state_ == RESUMING_INTERNAL)
1615     UpdateValidatorsOnResumption(new_create_info);
1616 
1617   // If the download is not parallel, clear the |received_slices_|.
1618   if (!received_slices_.empty() && !job_->IsParallelizable()) {
1619     destination_info_.received_bytes =
1620         GetMaxContiguousDataBlockSizeFromBeginning(received_slices_);
1621     received_slices_.clear();
1622   }
1623 
1624   TransitionTo(TARGET_PENDING_INTERNAL);
1625 
1626   job_->Start(download_file_.get(),
1627               base::BindRepeating(&DownloadItemImpl::OnDownloadFileInitialized,
1628                          weak_ptr_factory_.GetWeakPtr()),
1629               GetReceivedSlices());
1630 }
1631 
OnDownloadFileInitialized(DownloadInterruptReason result,int64_t bytes_wasted)1632 void DownloadItemImpl::OnDownloadFileInitialized(DownloadInterruptReason result,
1633                                                  int64_t bytes_wasted) {
1634   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1635   DCHECK(state_ == TARGET_PENDING_INTERNAL ||
1636          state_ == INTERRUPTED_TARGET_PENDING_INTERNAL)
1637       << "Unexpected state: " << DebugDownloadStateString(state_);
1638 
1639   DVLOG(20) << __func__
1640             << "() result:" << DownloadInterruptReasonToString(result);
1641 
1642   if (bytes_wasted > 0) {
1643     bytes_wasted_ += bytes_wasted;
1644     delegate_->ReportBytesWasted(this);
1645   }
1646 
1647   // Handle download interrupt reason.
1648   if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
1649     ReleaseDownloadFile(true);
1650     InterruptAndDiscardPartialState(result);
1651   }
1652 
1653   DetermineDownloadTarget();
1654 }
1655 
DetermineDownloadTarget()1656 void DownloadItemImpl::DetermineDownloadTarget() {
1657   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1658   DVLOG(20) << __func__ << "() " << DebugString(true);
1659 
1660   RecordDownloadCountWithSource(DETERMINE_DOWNLOAD_TARGET_COUNT,
1661                                 download_source_);
1662   delegate_->DetermineDownloadTarget(
1663       this, base::BindOnce(&DownloadItemImpl::OnDownloadTargetDetermined,
1664                        weak_ptr_factory_.GetWeakPtr()));
1665 }
1666 
1667 // Called by delegate_ when the download target path has been determined.
OnDownloadTargetDetermined(const base::FilePath & target_path,TargetDisposition disposition,DownloadDangerType danger_type,MixedContentStatus mixed_content_status,const base::FilePath & intermediate_path,base::Optional<DownloadSchedule> download_schedule,DownloadInterruptReason interrupt_reason)1668 void DownloadItemImpl::OnDownloadTargetDetermined(
1669     const base::FilePath& target_path,
1670     TargetDisposition disposition,
1671     DownloadDangerType danger_type,
1672     MixedContentStatus mixed_content_status,
1673     const base::FilePath& intermediate_path,
1674     base::Optional<DownloadSchedule> download_schedule,
1675     DownloadInterruptReason interrupt_reason) {
1676   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1677   if (state_ == CANCELLED_INTERNAL)
1678     return;
1679 
1680   DCHECK(state_ == TARGET_PENDING_INTERNAL ||
1681          state_ == INTERRUPTED_TARGET_PENDING_INTERNAL);
1682   DVLOG(20) << __func__ << "() target_path:" << target_path.value()
1683             << " intermediate_path:" << intermediate_path.value()
1684             << " disposition:" << disposition << " danger_type:" << danger_type
1685             << " interrupt_reason:"
1686             << DownloadInterruptReasonToString(interrupt_reason)
1687             << " this:" << DebugString(true);
1688 
1689   RecordDownloadCountWithSource(DOWNLOAD_TARGET_DETERMINED_COUNT,
1690                                 download_source_);
1691 
1692   if (IsCancellation(interrupt_reason) || target_path.empty()) {
1693     Cancel(true);
1694     return;
1695   }
1696 
1697   if (download_schedule)
1698     RecordDownloadLaterEvent(DownloadLaterEvent::kScheduleAdded);
1699   SwapDownloadSchedule(std::move(download_schedule));
1700 
1701   // There were no other pending errors, and we just failed to determined the
1702   // download target. The target path, if it is non-empty, should be considered
1703   // suspect. The safe option here is to interrupt the download without doing an
1704   // intermediate rename. In the case of a new download, we'll lose the partial
1705   // data that may have been downloaded, but that should be a small loss.
1706   if (state_ == TARGET_PENDING_INTERNAL &&
1707       interrupt_reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
1708     deferred_interrupt_reason_ = interrupt_reason;
1709     TransitionTo(INTERRUPTED_TARGET_PENDING_INTERNAL);
1710     OnTargetResolved();
1711     return;
1712   }
1713 
1714   destination_info_.target_path = target_path;
1715   destination_info_.target_disposition = disposition;
1716   SetDangerType(danger_type);
1717   mixed_content_status_ = mixed_content_status;
1718 
1719   // This was an interrupted download that was looking for a filename. Resolve
1720   // early without performing the intermediate rename. If there is a
1721   // DownloadFile, then that should be renamed to the intermediate name before
1722   // we can interrupt the download. Otherwise we may lose intermediate state.
1723   if (state_ == INTERRUPTED_TARGET_PENDING_INTERNAL && !download_file_) {
1724     OnTargetResolved();
1725     return;
1726   }
1727 
1728   // We want the intermediate and target paths to refer to the same directory so
1729   // that they are both on the same device and subject to same
1730   // space/permission/availability constraints.
1731   DCHECK(intermediate_path.DirName() == target_path.DirName());
1732 
1733   // During resumption, we may choose to proceed with the same intermediate
1734   // file. No rename is necessary if our intermediate file already has the
1735   // correct name.
1736   //
1737   // The intermediate name may change from its original value during filename
1738   // determination on resumption, for example if the reason for the interruption
1739   // was the download target running out space, resulting in a user prompt.
1740   if (intermediate_path == GetFullPath()) {
1741     OnDownloadRenamedToIntermediateName(DOWNLOAD_INTERRUPT_REASON_NONE,
1742                                         intermediate_path);
1743     return;
1744   }
1745 
1746   // Rename to intermediate name.
1747   // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a
1748   //               spurious rename when we can just rename to the final
1749   //               filename. Unnecessary renames may cause bugs like
1750   //               http://crbug.com/74187.
1751   DCHECK(!IsSavePackageDownload());
1752   DownloadFile::RenameCompletionCallback callback =
1753       base::BindOnce(&DownloadItemImpl::OnDownloadRenamedToIntermediateName,
1754                  weak_ptr_factory_.GetWeakPtr());
1755 #if defined(OS_ANDROID)
1756   if ((download_type_ == TYPE_ACTIVE_DOWNLOAD && !transient_ &&
1757        DownloadCollectionBridge::ShouldPublishDownload(GetTargetFilePath())) ||
1758       GetTargetFilePath().IsContentUri()) {
1759     GetDownloadTaskRunner()->PostTask(
1760         FROM_HERE,
1761         base::BindOnce(&DownloadFile::RenameToIntermediateUri,
1762                        // Safe because we control download file lifetime.
1763                        base::Unretained(download_file_.get()), GetOriginalUrl(),
1764                        GetReferrerUrl(), GetFileNameToReportUser(),
1765                        GetMimeType(), GetTargetFilePath(),
1766                        std::move(callback)));
1767     return;
1768   }
1769 #endif  // defined(OS_ANDROID)
1770 
1771   GetDownloadTaskRunner()->PostTask(
1772       FROM_HERE,
1773       base::BindOnce(&DownloadFile::RenameAndUniquify,
1774                      // Safe because we control download file lifetime.
1775                      base::Unretained(download_file_.get()), intermediate_path,
1776                      std::move(callback)));
1777 }
1778 
OnDownloadRenamedToIntermediateName(DownloadInterruptReason reason,const base::FilePath & full_path)1779 void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
1780     DownloadInterruptReason reason,
1781     const base::FilePath& full_path) {
1782   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1783   DCHECK(state_ == TARGET_PENDING_INTERNAL ||
1784          state_ == INTERRUPTED_TARGET_PENDING_INTERNAL);
1785   DCHECK(download_file_);
1786   DVLOG(20) << __func__ << "() download=" << DebugString(true);
1787 
1788   if (DOWNLOAD_INTERRUPT_REASON_NONE == reason) {
1789     SetFullPath(full_path);
1790 #if defined(OS_ANDROID)
1791     // For content URIs, target file path is the same as the current path.
1792     if (full_path.IsContentUri()) {
1793       destination_info_.target_path = full_path;
1794       if (display_name_.empty())
1795         SetDisplayName(download_file_->GetDisplayName());
1796     }
1797 #endif  // defined(OS_ANDROID)
1798   } else {
1799     // TODO(asanka): Even though the rename failed, it may still be possible to
1800     // recover the partial state from the 'before' name.
1801     deferred_interrupt_reason_ = reason;
1802     TransitionTo(INTERRUPTED_TARGET_PENDING_INTERNAL);
1803   }
1804   OnTargetResolved();
1805 }
1806 
OnTargetResolved()1807 void DownloadItemImpl::OnTargetResolved() {
1808   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1809   DVLOG(20) << __func__ << "() download=" << DebugString(true);
1810   DCHECK((state_ == TARGET_PENDING_INTERNAL &&
1811           deferred_interrupt_reason_ == DOWNLOAD_INTERRUPT_REASON_NONE) ||
1812          (state_ == INTERRUPTED_TARGET_PENDING_INTERNAL &&
1813           deferred_interrupt_reason_ != DOWNLOAD_INTERRUPT_REASON_NONE))
1814       << " deferred_interrupt_reason_:"
1815       << DownloadInterruptReasonToString(deferred_interrupt_reason_)
1816       << " this:" << DebugString(true);
1817 
1818   // This transition is here to ensure that the DownloadItemImpl state machine
1819   // doesn't transition to INTERRUPTED or IN_PROGRESS from
1820   // TARGET_PENDING_INTERNAL directly. Doing so without passing through
1821   // OnTargetResolved() can result in an externally visible state where the
1822   // download is interrupted but doesn't have a target path associated with it.
1823   //
1824   // While not terrible, this complicates the DownloadItem<->Observer
1825   // relationship since an observer that needs a target path in order to respond
1826   // properly to an interruption will need to wait for another OnDownloadUpdated
1827   // notification.  This requirement currently affects all of our UIs.
1828   TransitionTo(TARGET_RESOLVED_INTERNAL);
1829 
1830   if (DOWNLOAD_INTERRUPT_REASON_NONE != deferred_interrupt_reason_) {
1831     InterruptWithPartialState(GetReceivedBytes(), std::move(hash_state_),
1832                               deferred_interrupt_reason_);
1833     deferred_interrupt_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE;
1834     UpdateObservers();
1835     return;
1836   }
1837 
1838   // The download will be started later, interrupt it for now.
1839   if (MaybeDownloadLater()) {
1840     UpdateObservers();
1841     return;
1842   }
1843 
1844   download_schedule_ = base::nullopt;
1845 
1846   TransitionTo(IN_PROGRESS_INTERNAL);
1847   // TODO(asanka): Calling UpdateObservers() prior to MaybeCompleteDownload() is
1848   // not safe. The download could be in an underminate state after invoking
1849   // observers. http://crbug.com/586610
1850   UpdateObservers();
1851   MaybeCompleteDownload();
1852 }
1853 
MaybeDownloadLater()1854 bool DownloadItemImpl::MaybeDownloadLater() {
1855   if (!base::FeatureList::IsEnabled(features::kDownloadLater) ||
1856       !download_schedule_.has_value()) {
1857     return false;
1858   }
1859 
1860   if (ShouldDownloadLater()) {
1861     // TODO(xingliu): Maybe add a new interrupt reason for download later
1862     // feature.
1863     InterruptWithPartialState(GetReceivedBytes(), std::move(hash_state_),
1864                               DOWNLOAD_INTERRUPT_REASON_CRASH);
1865     return true;
1866   }
1867 
1868   return false;
1869 }
1870 
ShouldDownloadLater() const1871 bool DownloadItemImpl::ShouldDownloadLater() const {
1872   // No schedule, just proceed.
1873   if (!download_schedule_)
1874     return false;
1875 
1876   bool network_type_ok = !download_schedule_->only_on_wifi() ||
1877                          !delegate_->IsActiveNetworkMetered();
1878   bool should_start_later =
1879       download_schedule_->start_time().has_value() &&
1880       download_schedule_->start_time() > base::Time::Now();
1881 
1882   // Don't proceed if network requirement is not met or has a scheduled start
1883   // time.
1884   return !network_type_ok || should_start_later;
1885 }
1886 
SwapDownloadSchedule(base::Optional<DownloadSchedule> download_schedule)1887 void DownloadItemImpl::SwapDownloadSchedule(
1888     base::Optional<DownloadSchedule> download_schedule) {
1889   if (!base::FeatureList::IsEnabled(features::kDownloadLater))
1890     return;
1891   download_schedule_ = std::move(download_schedule);
1892   if (download_schedule_)
1893     allow_metered_ = !download_schedule_->only_on_wifi();
1894 }
1895 
1896 // When SavePackage downloads MHTML to GData (see
1897 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
1898 // does for non-SavePackage downloads, but SavePackage downloads never satisfy
1899 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
1900 // DownloadItem::UpdateObservers() when the upload completes so that
1901 // SavePackage notices that the upload has completed and runs its normal
1902 // Finish() pathway. MaybeCompleteDownload() is never the mechanism by which
1903 // SavePackage completes downloads. SavePackage always uses its own Finish() to
1904 // mark downloads complete.
MaybeCompleteDownload()1905 void DownloadItemImpl::MaybeCompleteDownload() {
1906   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1907   DCHECK(!IsSavePackageDownload());
1908 
1909   if (!IsDownloadReadyForCompletion(
1910           base::BindRepeating(&DownloadItemImpl::MaybeCompleteDownload,
1911                               weak_ptr_factory_.GetWeakPtr())))
1912     return;
1913   // Confirm we're in the proper set of states to be here; have all data, have a
1914   // history handle, (validated or safe).
1915   DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
1916   DCHECK(!IsDangerous());
1917   DCHECK(AllDataSaved());
1918 
1919   OnDownloadCompleting();
1920 }
1921 
1922 // Called by MaybeCompleteDownload() when it has determined that the download
1923 // is ready for completion.
OnDownloadCompleting()1924 void DownloadItemImpl::OnDownloadCompleting() {
1925   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1926 
1927   if (state_ != IN_PROGRESS_INTERNAL)
1928     return;
1929 
1930   DVLOG(20) << __func__ << "() " << DebugString(true);
1931   DCHECK(!GetTargetFilePath().empty());
1932   DCHECK(!IsDangerous());
1933 
1934   DCHECK(download_file_);
1935   // Unilaterally rename; even if it already has the right name,
1936   // we need theannotation.
1937   DownloadFile::RenameCompletionCallback callback =
1938       base::BindOnce(&DownloadItemImpl::OnDownloadRenamedToFinalName,
1939                  weak_ptr_factory_.GetWeakPtr());
1940 #if defined(OS_ANDROID)
1941   if (GetTargetFilePath().IsContentUri()) {
1942     GetDownloadTaskRunner()->PostTask(
1943         FROM_HERE,
1944         base::BindOnce(&DownloadFile::PublishDownload,
1945                        // Safe because we control download file lifetime.
1946                        base::Unretained(download_file_.get()),
1947                        std::move(callback)));
1948     return;
1949   }
1950 #endif  // defined(OS_ANDROID)
1951 
1952   mojo::PendingRemote<quarantine::mojom::Quarantine> quarantine;
1953   auto quarantine_callback = delegate_->GetQuarantineConnectionCallback();
1954   if (quarantine_callback)
1955     quarantine_callback.Run(quarantine.InitWithNewPipeAndPassReceiver());
1956   GetDownloadTaskRunner()->PostTask(
1957       FROM_HERE,
1958       base::BindOnce(&DownloadFile::RenameAndAnnotate,
1959                      base::Unretained(download_file_.get()),
1960                      GetTargetFilePath(),
1961                      delegate_->GetApplicationClientIdForFileScanning(),
1962                      delegate_->IsOffTheRecord() ? GURL() : GetURL(),
1963                      delegate_->IsOffTheRecord() ? GURL() : GetReferrerUrl(),
1964                      std::move(quarantine), std::move(callback)));
1965 }
1966 
OnDownloadRenamedToFinalName(DownloadInterruptReason reason,const base::FilePath & full_path)1967 void DownloadItemImpl::OnDownloadRenamedToFinalName(
1968     DownloadInterruptReason reason,
1969     const base::FilePath& full_path) {
1970   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1971   DCHECK(!IsSavePackageDownload());
1972 
1973   // If a cancel or interrupt hit, we'll cancel the DownloadFile, which
1974   // will result in deleting the file on the file thread.  So we don't
1975   // care about the name having been changed.
1976   if (state_ != IN_PROGRESS_INTERNAL)
1977     return;
1978 
1979   DVLOG(20) << __func__ << "() full_path = \"" << full_path.value() << "\" "
1980             << DebugString(false);
1981 
1982   if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
1983     // Failure to perform the final rename is considered fatal. TODO(asanka): It
1984     // may not be, in which case we should figure out whether we can recover the
1985     // state.
1986     InterruptAndDiscardPartialState(reason);
1987     UpdateObservers();
1988     return;
1989   }
1990 
1991   DCHECK(GetTargetFilePath() == full_path);
1992 
1993   if (full_path != GetFullPath()) {
1994     // full_path is now the current and target file path.
1995     DCHECK(!full_path.empty());
1996     SetFullPath(full_path);
1997   }
1998 
1999   // Complete the download and release the DownloadFile.
2000   DCHECK(download_file_);
2001   ReleaseDownloadFile(false);
2002 
2003   // We're not completely done with the download item yet, but at this
2004   // point we're committed to complete the download.  Cancels (or Interrupts,
2005   // though it's not clear how they could happen) after this point will be
2006   // ignored.
2007   TransitionTo(COMPLETING_INTERNAL);
2008 
2009   if (delegate_->ShouldOpenDownload(
2010           this, base::BindOnce(&DownloadItemImpl::DelayedDownloadOpened,
2011                                weak_ptr_factory_.GetWeakPtr()))) {
2012     Completed();
2013   } else {
2014     delegate_delayed_complete_ = true;
2015     UpdateObservers();
2016   }
2017 }
2018 
DelayedDownloadOpened(bool auto_opened)2019 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
2020   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2021 
2022   auto_opened_ = auto_opened;
2023   Completed();
2024 }
2025 
Completed()2026 void DownloadItemImpl::Completed() {
2027   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2028 
2029   DVLOG(20) << __func__ << "() " << DebugString(false);
2030 
2031   DCHECK(AllDataSaved());
2032   destination_info_.end_time = base::Time::Now();
2033   TransitionTo(COMPLETE_INTERNAL);
2034 
2035   bool is_parallelizable = job_ && job_->IsParallelizable();
2036   RecordDownloadCompleted(GetReceivedBytes(), is_parallelizable,
2037                           net::NetworkChangeNotifier::GetConnectionType(),
2038                           download_source_);
2039   if (!delegate_->IsOffTheRecord()) {
2040     RecordDownloadCountWithSource(COMPLETED_COUNT_NORMAL_PROFILE,
2041                                   download_source_);
2042   }
2043   if (is_parallelizable) {
2044     RecordParallelizableDownloadCount(COMPLETED_COUNT,
2045                                       IsParallelDownloadEnabled());
2046     int64_t content_length = -1;
2047     if (response_headers_->response_code() != net::HTTP_PARTIAL_CONTENT) {
2048       content_length = response_headers_->GetContentLength();
2049     } else {
2050       int64_t first_byte = -1;
2051       int64_t last_byte = -1;
2052       response_headers_->GetContentRangeFor206(&first_byte, &last_byte,
2053                                                &content_length);
2054     }
2055   }
2056 
2057   if (auto_opened_) {
2058     // If it was already handled by the delegate, do nothing.
2059   } else if (GetOpenWhenComplete() || ShouldOpenFileBasedOnExtension() ||
2060              IsTemporary()) {
2061     // If the download is temporary, like in drag-and-drop, do not open it but
2062     // we still need to set it auto-opened so that it can be removed from the
2063     // download shelf.
2064     if (!IsTemporary())
2065       OpenDownload();
2066 
2067     auto_opened_ = true;
2068   }
2069 
2070   base::TimeDelta time_since_start = GetEndTime() - GetStartTime();
2071 
2072   // If all data is saved, the number of received bytes is resulting file size.
2073   int resulting_file_size = GetReceivedBytes();
2074 
2075   DownloadUkmHelper::RecordDownloadCompleted(
2076       ukm_download_id_, resulting_file_size, time_since_start, bytes_wasted_);
2077 
2078   // After all of the records are done, then update the observers.
2079   UpdateObservers();
2080 }
2081 
2082 // **** End of Download progression cascade
2083 
InterruptAndDiscardPartialState(DownloadInterruptReason reason)2084 void DownloadItemImpl::InterruptAndDiscardPartialState(
2085     DownloadInterruptReason reason) {
2086   InterruptWithPartialState(0, nullptr, reason);
2087 }
2088 
InterruptWithPartialState(int64_t bytes_so_far,std::unique_ptr<crypto::SecureHash> hash_state,DownloadInterruptReason reason)2089 void DownloadItemImpl::InterruptWithPartialState(
2090     int64_t bytes_so_far,
2091     std::unique_ptr<crypto::SecureHash> hash_state,
2092     DownloadInterruptReason reason) {
2093   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2094   DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason);
2095   DVLOG(20) << __func__
2096             << "() reason:" << DownloadInterruptReasonToString(reason)
2097             << " bytes_so_far:" << bytes_so_far
2098             << " hash_state:" << (hash_state ? "Valid" : "Invalid")
2099             << " this=" << DebugString(true);
2100 
2101   // Somewhat counter-intuitively, it is possible for us to receive an
2102   // interrupt after we've already been interrupted.  The generation of
2103   // interrupts from the file thread Renames and the generation of
2104   // interrupts from disk writes go through two different mechanisms (driven
2105   // by rename requests from UI thread and by write requests from IO thread,
2106   // respectively), and since we choose not to keep state on the File thread,
2107   // this is the place where the races collide.  It's also possible for
2108   // interrupts to race with cancels.
2109   switch (state_) {
2110     case CANCELLED_INTERNAL:
2111     // If the download is already cancelled, then there's no point in
2112     // transitioning out to interrupted.
2113     case COMPLETING_INTERNAL:
2114     case COMPLETE_INTERNAL:
2115       // Already complete.
2116       return;
2117 
2118     case INITIAL_INTERNAL:
2119     case MAX_DOWNLOAD_INTERNAL_STATE:
2120       NOTREACHED();
2121       return;
2122 
2123     case TARGET_PENDING_INTERNAL:
2124     case INTERRUPTED_TARGET_PENDING_INTERNAL:
2125       // Postpone recognition of this error until after file name determination
2126       // has completed and the intermediate file has been renamed to simplify
2127       // resumption conditions. The target determination logic is much simpler
2128       // if the state of the download remains constant until that stage
2129       // completes.
2130       //
2131       // current_path_ may be empty because it is possible for
2132       // DownloadItem to receive a DestinationError prior to the
2133       // download file initialization complete callback.
2134       if (!IsCancellation(reason)) {
2135         UpdateProgress(bytes_so_far, 0);
2136         SetHashState(std::move(hash_state));
2137         deferred_interrupt_reason_ = reason;
2138         TransitionTo(INTERRUPTED_TARGET_PENDING_INTERNAL);
2139         return;
2140       }
2141       // else - Fallthrough for cancellation handling which is equivalent to the
2142       // IN_PROGRESS state.
2143       FALLTHROUGH;
2144 
2145     case IN_PROGRESS_INTERNAL:
2146     case TARGET_RESOLVED_INTERNAL: {
2147       // last_reason_ needs to be set for GetResumeMode() to work.
2148       last_reason_ = reason;
2149 
2150       ResumeMode resume_mode = GetResumeMode();
2151       ReleaseDownloadFile(resume_mode != ResumeMode::IMMEDIATE_CONTINUE &&
2152                           resume_mode != ResumeMode::USER_CONTINUE);
2153     } break;
2154 
2155     case RESUMING_INTERNAL:
2156     case INTERRUPTED_INTERNAL:
2157       DCHECK(!download_file_);
2158       // The first non-cancel interrupt reason wins in cases where multiple
2159       // things go wrong.
2160       if (!IsCancellation(reason))
2161         return;
2162 
2163       last_reason_ = reason;
2164       // There is no download file and this is transitioning from INTERRUPTED
2165       // to CANCELLED. The intermediate file is no longer usable, and should
2166       // be deleted.
2167       DeleteDownloadFile();
2168       break;
2169   }
2170 
2171   // Reset all data saved, as even if we did save all the data we're going to go
2172   // through another round of downloading when we resume. There's a potential
2173   // problem here in the abstract, as if we did download all the data and then
2174   // run into a continuable error, on resumption we won't download any more
2175   // data.  However, a) there are currently no continuable errors that can occur
2176   // after we download all the data, and b) if there were, that would probably
2177   // simply result in a null range request, which would generate a
2178   // DestinationCompleted() notification from the DownloadFile, which would
2179   // behave properly with setting all_data_saved_ to false here.
2180   destination_info_.all_data_saved = false;
2181 
2182   if (GetFullPath().empty()) {
2183     hash_state_.reset();
2184     destination_info_.hash.clear();
2185     destination_info_.received_bytes = 0;
2186     received_slices_.clear();
2187   } else {
2188     UpdateProgress(bytes_so_far, 0);
2189     SetHashState(std::move(hash_state));
2190   }
2191 
2192   if (job_)
2193     job_->Cancel(false);
2194 
2195   if (IsCancellation(reason)) {
2196     RecordDownloadCountWithSource(CANCELLED_COUNT, download_source_);
2197     if (job_ && job_->IsParallelizable()) {
2198       RecordParallelizableDownloadCount(CANCELLED_COUNT,
2199                                         IsParallelDownloadEnabled());
2200     }
2201     DCHECK_EQ(last_reason_, reason);
2202     TransitionTo(CANCELLED_INTERNAL);
2203     return;
2204   }
2205 
2206   RecordDownloadInterrupted(reason, GetReceivedBytes(), total_bytes_,
2207                             job_ && job_->IsParallelizable(),
2208                             IsParallelDownloadEnabled(), download_source_);
2209 
2210   base::TimeDelta time_since_start = base::Time::Now() - GetStartTime();
2211   int resulting_file_size = GetReceivedBytes();
2212   base::Optional<int> change_in_file_size;
2213   if (total_bytes_ >= 0) {
2214     change_in_file_size = total_bytes_ - resulting_file_size;
2215   }
2216 
2217   DownloadUkmHelper::RecordDownloadInterrupted(
2218       ukm_download_id_, change_in_file_size, reason, resulting_file_size,
2219       time_since_start, bytes_wasted_);
2220   if (reason == DOWNLOAD_INTERRUPT_REASON_SERVER_CONTENT_LENGTH_MISMATCH) {
2221     received_bytes_at_length_mismatch_ = GetReceivedBytes();
2222   }
2223 
2224   // TODO(asanka): This is not good. We can transition to interrupted from
2225   // target-pending, which is something we don't want to do. Perhaps we should
2226   // explicitly transition to target-resolved prior to switching to interrupted.
2227   DCHECK_EQ(last_reason_, reason);
2228   TransitionTo(INTERRUPTED_INTERNAL);
2229   delegate_->DownloadInterrupted(this);
2230   AutoResumeIfValid();
2231 }
2232 
UpdateProgress(int64_t bytes_so_far,int64_t bytes_per_sec)2233 void DownloadItemImpl::UpdateProgress(int64_t bytes_so_far,
2234                                       int64_t bytes_per_sec) {
2235   destination_info_.received_bytes = bytes_so_far;
2236   bytes_per_sec_ = bytes_per_sec;
2237 
2238   // If we've received more data than we were expecting (bad server info?),
2239   // revert to 'unknown size mode'.
2240   if (bytes_so_far > total_bytes_)
2241     total_bytes_ = 0;
2242 }
2243 
SetHashState(std::unique_ptr<crypto::SecureHash> hash_state)2244 void DownloadItemImpl::SetHashState(
2245     std::unique_ptr<crypto::SecureHash> hash_state) {
2246   hash_state_ = std::move(hash_state);
2247   if (!hash_state_) {
2248     destination_info_.hash.clear();
2249     return;
2250   }
2251 
2252   std::unique_ptr<crypto::SecureHash> clone_of_hash_state(hash_state_->Clone());
2253   std::vector<char> hash_value(clone_of_hash_state->GetHashLength());
2254   clone_of_hash_state->Finish(&hash_value.front(), hash_value.size());
2255   destination_info_.hash.assign(hash_value.begin(), hash_value.end());
2256 }
2257 
ReleaseDownloadFile(bool destroy_file)2258 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) {
2259   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2260   DVLOG(20) << __func__ << "() destroy_file:" << destroy_file;
2261 
2262   if (destroy_file) {
2263     if (download_file_) {
2264       GetDownloadTaskRunner()->PostTask(
2265           FROM_HERE,
2266           // Will be deleted at end of task execution.
2267           base::BindOnce(&DownloadFileCancel, std::move(download_file_)));
2268     } else {
2269       DeleteDownloadFile();
2270     }
2271     // Avoid attempting to reuse the intermediate file by clearing out
2272     // current_path_ and received slices.
2273     destination_info_.current_path.clear();
2274     received_slices_.clear();
2275   } else if (download_file_) {
2276     GetDownloadTaskRunner()->PostTask(
2277         FROM_HERE, base::BindOnce(base::IgnoreResult(&DownloadFileDetach),
2278                                   // Will be deleted at end of task execution.
2279                                   std::move(download_file_)));
2280   }
2281   // Don't accept any more messages from the DownloadFile, and null
2282   // out any previous "all data received".  This also breaks links to
2283   // other entities we've given out weak pointers to.
2284   weak_ptr_factory_.InvalidateWeakPtrs();
2285 }
2286 
DeleteDownloadFile()2287 void DownloadItemImpl::DeleteDownloadFile() {
2288   if (GetFullPath().empty())
2289     return;
2290   GetDownloadTaskRunner()->PostTask(
2291       FROM_HERE,
2292       base::BindOnce(base::IgnoreResult(&DeleteDownloadedFile), GetFullPath()));
2293   destination_info_.current_path.clear();
2294 }
2295 
IsDownloadReadyForCompletion(base::OnceClosure state_change_notification)2296 bool DownloadItemImpl::IsDownloadReadyForCompletion(
2297     base::OnceClosure state_change_notification) {
2298   // If the download hasn't progressed to the IN_PROGRESS state, then it's not
2299   // ready for completion.
2300   if (state_ != IN_PROGRESS_INTERNAL)
2301     return false;
2302 
2303   // If we don't have all the data, the download is not ready for
2304   // completion.
2305   if (!AllDataSaved())
2306     return false;
2307 
2308   // If the download is dangerous, but not yet validated, it's not ready for
2309   // completion.
2310   if (IsDangerous())
2311     return false;
2312 
2313   // If the download is mixed content, but not yet validated, it's not ready for
2314   // completion.
2315   if (IsMixedContent())
2316     return false;
2317 
2318   // Check for consistency before invoking delegate. Since there are no pending
2319   // target determination calls and the download is in progress, both the target
2320   // and current paths should be non-empty and they should point to the same
2321   // directory.
2322   DCHECK(!GetTargetFilePath().empty());
2323   DCHECK(!GetFullPath().empty());
2324   DCHECK(GetTargetFilePath().DirName() == GetFullPath().DirName());
2325 
2326   // Give the delegate a chance to hold up a stop sign.  It'll call
2327   // use back through the passed callback if it does and that state changes.
2328   if (!delegate_->ShouldCompleteDownload(this,
2329                                          std::move(state_change_notification)))
2330     return false;
2331 
2332   return true;
2333 }
2334 
TransitionTo(DownloadInternalState new_state)2335 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
2336   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2337 
2338   if (state_ == new_state)
2339     return;
2340 
2341   DownloadInternalState old_state = state_;
2342   state_ = new_state;
2343 
2344   DCHECK(IsSavePackageDownload()
2345              ? IsValidSavePackageStateTransition(old_state, new_state)
2346              : IsValidStateTransition(old_state, new_state))
2347       << "Invalid state transition from:" << DebugDownloadStateString(old_state)
2348       << " to:" << DebugDownloadStateString(new_state);
2349 
2350   switch (state_) {
2351     case INITIAL_INTERNAL:
2352       NOTREACHED();
2353       break;
2354 
2355     case TARGET_PENDING_INTERNAL:
2356     case TARGET_RESOLVED_INTERNAL:
2357       break;
2358 
2359     case INTERRUPTED_TARGET_PENDING_INTERNAL:
2360       DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, deferred_interrupt_reason_)
2361           << "Interrupt reason must be set prior to transitioning into "
2362              "TARGET_PENDING";
2363       break;
2364 
2365     case IN_PROGRESS_INTERNAL:
2366       DCHECK(!GetFullPath().empty()) << "Current output path must be known.";
2367       DCHECK(!GetTargetFilePath().empty()) << "Target path must be known.";
2368       DCHECK(GetFullPath().DirName() == GetTargetFilePath().DirName())
2369           << "Current output directory must match target directory.";
2370       DCHECK(download_file_) << "Output file must be owned by download item.";
2371       DCHECK(job_) << "Must have active download job.";
2372       DCHECK(!job_->is_paused())
2373           << "At the time a download enters IN_PROGRESS state, "
2374              "it must not be paused.";
2375       break;
2376 
2377     case COMPLETING_INTERNAL:
2378       DCHECK(AllDataSaved()) << "All data must be saved prior to completion.";
2379       DCHECK(!download_file_)
2380           << "Download file must be released prior to completion.";
2381       DCHECK(!GetTargetFilePath().empty()) << "Target path must be known.";
2382       DCHECK(GetFullPath() == GetTargetFilePath())
2383           << "Current output path must match target path.";
2384 
2385       TRACE_EVENT_INSTANT2("download", "DownloadItemCompleting",
2386                            TRACE_EVENT_SCOPE_THREAD, "bytes_so_far",
2387                            GetReceivedBytes(), "final_hash",
2388                            destination_info_.hash);
2389       break;
2390 
2391     case COMPLETE_INTERNAL:
2392       TRACE_EVENT_INSTANT1("download", "DownloadItemFinished",
2393                            TRACE_EVENT_SCOPE_THREAD, "auto_opened",
2394                            auto_opened_ ? "yes" : "no");
2395       break;
2396 
2397     case INTERRUPTED_INTERNAL:
2398       DCHECK(!download_file_)
2399           << "Download file must be released prior to interruption.";
2400       DCHECK_NE(last_reason_, DOWNLOAD_INTERRUPT_REASON_NONE);
2401       TRACE_EVENT_INSTANT2("download", "DownloadItemInterrupted",
2402                            TRACE_EVENT_SCOPE_THREAD, "interrupt_reason",
2403                            DownloadInterruptReasonToString(last_reason_),
2404                            "bytes_so_far", GetReceivedBytes());
2405       break;
2406 
2407     case RESUMING_INTERNAL:
2408       TRACE_EVENT_INSTANT2("download", "DownloadItemResumed",
2409                            TRACE_EVENT_SCOPE_THREAD, "interrupt_reason",
2410                            DownloadInterruptReasonToString(last_reason_),
2411                            "bytes_so_far", GetReceivedBytes());
2412       break;
2413 
2414     case CANCELLED_INTERNAL:
2415       TRACE_EVENT_INSTANT1("download", "DownloadItemCancelled",
2416                            TRACE_EVENT_SCOPE_THREAD, "bytes_so_far",
2417                            GetReceivedBytes());
2418       break;
2419 
2420     case MAX_DOWNLOAD_INTERNAL_STATE:
2421       NOTREACHED();
2422       break;
2423   }
2424 
2425   DVLOG(20) << __func__ << "() from:" << DebugDownloadStateString(old_state)
2426             << " to:" << DebugDownloadStateString(state_)
2427             << " this = " << DebugString(true);
2428   bool is_done =
2429       (state_ == COMPLETE_INTERNAL || state_ == INTERRUPTED_INTERNAL ||
2430        state_ == RESUMING_INTERNAL || state_ == CANCELLED_INTERNAL);
2431   bool was_done =
2432       (old_state == COMPLETE_INTERNAL || old_state == INTERRUPTED_INTERNAL ||
2433        old_state == RESUMING_INTERNAL || old_state == CANCELLED_INTERNAL);
2434 
2435   // Termination
2436   if (is_done && !was_done)
2437     TRACE_EVENT_ASYNC_END0("download", "DownloadItemActive", download_id_);
2438 
2439   // Resumption
2440   if (was_done && !is_done) {
2441     std::string file_name(GetTargetFilePath().BaseName().AsUTF8Unsafe());
2442     TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
2443         "download", "DownloadItemActive", download_id_, "download_item",
2444         std::make_unique<DownloadItemActivatedData>(
2445             TYPE_ACTIVE_DOWNLOAD, GetId(), GetOriginalUrl().spec(),
2446             GetURL().spec(), file_name, GetDangerType(), GetReceivedBytes(),
2447             HasUserGesture()));
2448   }
2449 }
2450 
SetDangerType(DownloadDangerType danger_type)2451 void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
2452   if (danger_type != danger_type_) {
2453     TRACE_EVENT_INSTANT1("download", "DownloadItemSaftyStateUpdated",
2454                          TRACE_EVENT_SCOPE_THREAD, "danger_type",
2455                          GetDownloadDangerNames(danger_type).c_str());
2456   }
2457   danger_type_ = danger_type;
2458 }
2459 
SetFullPath(const base::FilePath & new_path)2460 void DownloadItemImpl::SetFullPath(const base::FilePath& new_path) {
2461   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2462   DVLOG(20) << __func__ << "() new_path = \"" << new_path.value() << "\" "
2463             << DebugString(true);
2464   DCHECK(!new_path.empty());
2465 
2466   TRACE_EVENT_INSTANT2("download", "DownloadItemRenamed",
2467                        TRACE_EVENT_SCOPE_THREAD, "old_filename",
2468                        destination_info_.current_path.AsUTF8Unsafe(),
2469                        "new_filename", new_path.AsUTF8Unsafe());
2470 
2471   destination_info_.current_path = new_path;
2472 }
2473 
AutoResumeIfValid()2474 void DownloadItemImpl::AutoResumeIfValid() {
2475   DVLOG(20) << __func__ << "() " << DebugString(true);
2476   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2477 
2478   if (download_schedule_.has_value())
2479     return;
2480 
2481   ResumeMode mode = GetResumeMode();
2482   if (mode != ResumeMode::IMMEDIATE_RESTART &&
2483       mode != ResumeMode::IMMEDIATE_CONTINUE) {
2484     return;
2485   }
2486 
2487   auto_resume_count_++;
2488 
2489   ResumeInterruptedDownload(ResumptionRequestSource::AUTOMATIC);
2490 }
2491 
ResumeInterruptedDownload(ResumptionRequestSource source)2492 void DownloadItemImpl::ResumeInterruptedDownload(
2493     ResumptionRequestSource source) {
2494   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2495   // If we're not interrupted, ignore the request; our caller is drunk.
2496   if (state_ != INTERRUPTED_INTERNAL)
2497     return;
2498 
2499   // We are starting a new request. Shake off all pending operations.
2500   CHECK(!download_file_);
2501   weak_ptr_factory_.InvalidateWeakPtrs();
2502 
2503   // Reset the appropriate state if restarting.
2504   ResumeMode mode = GetResumeMode();
2505   if (mode == ResumeMode::IMMEDIATE_RESTART ||
2506       mode == ResumeMode::USER_RESTART) {
2507     LOG_IF(ERROR, !GetFullPath().empty())
2508         << "Download full path should be empty before resumption";
2509     if (destination_info_.received_bytes > 0) {
2510       RecordResumptionRestartReason(last_reason_);
2511     }
2512     destination_info_.received_bytes = 0;
2513     last_modified_time_.clear();
2514     etag_.clear();
2515     destination_info_.hash.clear();
2516     hash_state_.reset();
2517     received_slices_.clear();
2518   }
2519 
2520   net::NetworkTrafficAnnotationTag traffic_annotation =
2521       net::DefineNetworkTrafficAnnotation("download_manager_resume", R"(
2522         semantics {
2523           sender: "Download Manager"
2524           description:
2525             "When user resumes downloading a file, a network request is made "
2526             "to fetch it."
2527           trigger:
2528             "User resumes a download."
2529           data: "None."
2530           destination: WEBSITE
2531         }
2532         policy {
2533           cookies_allowed: YES
2534           cookies_store: "user"
2535           setting:
2536             "This feature cannot be disabled in settings, but it is activated "
2537             "by direct user action."
2538           chrome_policy {
2539             DownloadRestrictions {
2540               DownloadRestrictions: 3
2541             }
2542           }
2543         })");
2544   // Avoid using the WebContents even if it's still around. Resumption requests
2545   // are consistently routed through the no-renderer code paths so that the
2546   // request will not be dropped if the WebContents (and by extension, the
2547   // associated renderer) goes away before a response is received.
2548   std::unique_ptr<DownloadUrlParameters> download_params(
2549       new DownloadUrlParameters(GetURL(), traffic_annotation));
2550   download_params->set_file_path(GetFullPath());
2551   if (received_slices_.size() > 0) {
2552     std::vector<DownloadItem::ReceivedSlice> slices_to_download =
2553         FindSlicesToDownload(received_slices_);
2554     download_params->set_offset(slices_to_download[0].offset);
2555   } else {
2556     download_params->set_offset(GetReceivedBytes());
2557   }
2558   download_params->set_last_modified(GetLastModifiedTime());
2559   download_params->set_etag(GetETag());
2560   download_params->set_hash_of_partial_file(GetHash());
2561   download_params->set_hash_state(std::move(hash_state_));
2562   download_params->set_guid(guid_);
2563   if (!HasStrongValidators() &&
2564       base::FeatureList::IsEnabled(
2565           features::kAllowDownloadResumptionWithoutStrongValidators)) {
2566     int64_t validation_length = GetDownloadValidationLengthConfig();
2567     if (download_params->offset() > validation_length) {
2568       // There is enough data for validation, set the file_offset so
2569       // DownloadFileImpl will validate the data between offset to
2570       // file_offset.
2571       download_params->set_use_if_range(false);
2572       download_params->set_file_offset(download_params->offset());
2573       download_params->set_offset(download_params->offset() -
2574                                   validation_length);
2575     } else {
2576       // There is not enough data for validation, simply overwrites the
2577       // existing data from the beginning.
2578       download_params->set_offset(0);
2579     }
2580   }
2581 
2582   // TODO(xingliu): Read |fetch_error_body| and |request_headers_| from the
2583   // cache, and don't copy them into DownloadItemImpl.
2584   download_params->set_fetch_error_body(fetch_error_body_);
2585   for (const auto& header : request_headers_) {
2586     download_params->add_request_header(header.first, header.second);
2587   }
2588   // The offset is calculated after decompression, so the range request cannot
2589   // involve any compression,
2590   download_params->add_request_header("Accept-Encoding", "identity");
2591 
2592   // Note that resumed downloads disallow redirects. Hence the referrer URL
2593   // (which is the contents of the Referer header for the last download request)
2594   // will only be sent to the URL returned by GetURL().
2595   download_params->set_referrer(GetReferrerUrl());
2596   download_params->set_referrer_policy(net::ReferrerPolicy::NEVER_CLEAR);
2597   download_params->set_cross_origin_redirects(
2598       network::mojom::RedirectMode::kError);
2599 
2600   TransitionTo(RESUMING_INTERNAL);
2601   RecordDownloadCountWithSource(source == ResumptionRequestSource::USER
2602                                     ? MANUAL_RESUMPTION_COUNT
2603                                     : AUTO_RESUMPTION_COUNT,
2604                                 download_source_);
2605 
2606   base::TimeDelta time_since_start = base::Time::Now() - GetStartTime();
2607   DownloadUkmHelper::RecordDownloadResumed(ukm_download_id_, GetResumeMode(),
2608                                            time_since_start);
2609 
2610   delegate_->ResumeInterruptedDownload(std::move(download_params),
2611                                        request_info_.site_url);
2612 
2613   if (job_)
2614     job_->Resume(false);
2615 }
2616 
2617 // static
InternalToExternalState(DownloadInternalState internal_state)2618 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
2619     DownloadInternalState internal_state) {
2620   switch (internal_state) {
2621     case INITIAL_INTERNAL:
2622     case TARGET_PENDING_INTERNAL:
2623     case TARGET_RESOLVED_INTERNAL:
2624     case INTERRUPTED_TARGET_PENDING_INTERNAL:
2625     // TODO(asanka): Introduce an externally visible state to distinguish
2626     // between the above states and IN_PROGRESS_INTERNAL. The latter (the
2627     // state where the download is active and has a known target) is the state
2628     // that most external users are interested in.
2629     case IN_PROGRESS_INTERNAL:
2630       return IN_PROGRESS;
2631     case COMPLETING_INTERNAL:
2632       return IN_PROGRESS;
2633     case COMPLETE_INTERNAL:
2634       return COMPLETE;
2635     case CANCELLED_INTERNAL:
2636       return CANCELLED;
2637     case INTERRUPTED_INTERNAL:
2638       return INTERRUPTED;
2639     case RESUMING_INTERNAL:
2640       return IN_PROGRESS;
2641     case MAX_DOWNLOAD_INTERNAL_STATE:
2642       break;
2643   }
2644   NOTREACHED();
2645   return MAX_DOWNLOAD_STATE;
2646 }
2647 
2648 // static
2649 DownloadItemImpl::DownloadInternalState
ExternalToInternalState(DownloadState external_state)2650 DownloadItemImpl::ExternalToInternalState(DownloadState external_state) {
2651   switch (external_state) {
2652     case IN_PROGRESS:
2653       return IN_PROGRESS_INTERNAL;
2654     case COMPLETE:
2655       return COMPLETE_INTERNAL;
2656     case CANCELLED:
2657       return CANCELLED_INTERNAL;
2658     case INTERRUPTED:
2659       return INTERRUPTED_INTERNAL;
2660     default:
2661       NOTREACHED();
2662   }
2663   return MAX_DOWNLOAD_INTERNAL_STATE;
2664 }
2665 
2666 // static
IsValidSavePackageStateTransition(DownloadInternalState from,DownloadInternalState to)2667 bool DownloadItemImpl::IsValidSavePackageStateTransition(
2668     DownloadInternalState from,
2669     DownloadInternalState to) {
2670 #if DCHECK_IS_ON()
2671   switch (from) {
2672     case INITIAL_INTERNAL:
2673     case TARGET_PENDING_INTERNAL:
2674     case INTERRUPTED_TARGET_PENDING_INTERNAL:
2675     case TARGET_RESOLVED_INTERNAL:
2676     case COMPLETING_INTERNAL:
2677     case COMPLETE_INTERNAL:
2678     case INTERRUPTED_INTERNAL:
2679     case RESUMING_INTERNAL:
2680     case CANCELLED_INTERNAL:
2681       return false;
2682 
2683     case IN_PROGRESS_INTERNAL:
2684       return to == CANCELLED_INTERNAL || to == COMPLETE_INTERNAL;
2685 
2686     case MAX_DOWNLOAD_INTERNAL_STATE:
2687       NOTREACHED();
2688   }
2689   return false;
2690 #else
2691   return true;
2692 #endif
2693 }
2694 
2695 // static
IsValidStateTransition(DownloadInternalState from,DownloadInternalState to)2696 bool DownloadItemImpl::IsValidStateTransition(DownloadInternalState from,
2697                                               DownloadInternalState to) {
2698 #if DCHECK_IS_ON()
2699   switch (from) {
2700     case INITIAL_INTERNAL:
2701       return to == TARGET_PENDING_INTERNAL ||
2702              to == INTERRUPTED_TARGET_PENDING_INTERNAL;
2703 
2704     case TARGET_PENDING_INTERNAL:
2705       return to == INTERRUPTED_TARGET_PENDING_INTERNAL ||
2706              to == TARGET_RESOLVED_INTERNAL || to == CANCELLED_INTERNAL;
2707 
2708     case INTERRUPTED_TARGET_PENDING_INTERNAL:
2709       return to == TARGET_RESOLVED_INTERNAL || to == CANCELLED_INTERNAL;
2710 
2711     case TARGET_RESOLVED_INTERNAL:
2712       return to == IN_PROGRESS_INTERNAL || to == INTERRUPTED_INTERNAL ||
2713              to == CANCELLED_INTERNAL;
2714 
2715     case IN_PROGRESS_INTERNAL:
2716       return to == COMPLETING_INTERNAL || to == CANCELLED_INTERNAL ||
2717              to == INTERRUPTED_INTERNAL;
2718 
2719     case COMPLETING_INTERNAL:
2720       return to == COMPLETE_INTERNAL;
2721 
2722     case COMPLETE_INTERNAL:
2723       return false;
2724 
2725     case INTERRUPTED_INTERNAL:
2726       return to == RESUMING_INTERNAL || to == CANCELLED_INTERNAL;
2727 
2728     case RESUMING_INTERNAL:
2729       return to == TARGET_PENDING_INTERNAL ||
2730              to == INTERRUPTED_TARGET_PENDING_INTERNAL ||
2731              to == TARGET_RESOLVED_INTERNAL || to == CANCELLED_INTERNAL;
2732 
2733     case CANCELLED_INTERNAL:
2734       return false;
2735 
2736     case MAX_DOWNLOAD_INTERNAL_STATE:
2737       NOTREACHED();
2738   }
2739   return false;
2740 #else
2741   return true;
2742 #endif  // DCHECK_IS_ON()
2743 }
2744 
DebugDownloadStateString(DownloadInternalState state)2745 const char* DownloadItemImpl::DebugDownloadStateString(
2746     DownloadInternalState state) {
2747   switch (state) {
2748     case INITIAL_INTERNAL:
2749       return "INITIAL";
2750     case TARGET_PENDING_INTERNAL:
2751       return "TARGET_PENDING";
2752     case INTERRUPTED_TARGET_PENDING_INTERNAL:
2753       return "INTERRUPTED_TARGET_PENDING";
2754     case TARGET_RESOLVED_INTERNAL:
2755       return "TARGET_RESOLVED";
2756     case IN_PROGRESS_INTERNAL:
2757       return "IN_PROGRESS";
2758     case COMPLETING_INTERNAL:
2759       return "COMPLETING";
2760     case COMPLETE_INTERNAL:
2761       return "COMPLETE";
2762     case CANCELLED_INTERNAL:
2763       return "CANCELLED";
2764     case INTERRUPTED_INTERNAL:
2765       return "INTERRUPTED";
2766     case RESUMING_INTERNAL:
2767       return "RESUMING";
2768     case MAX_DOWNLOAD_INTERNAL_STATE:
2769       break;
2770   }
2771   NOTREACHED() << "Unknown download state " << state;
2772   return "unknown";
2773 }
2774 
DebugResumeModeString(ResumeMode mode)2775 const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) {
2776   switch (mode) {
2777     case ResumeMode::INVALID:
2778       return "INVALID";
2779     case ResumeMode::IMMEDIATE_CONTINUE:
2780       return "IMMEDIATE_CONTINUE";
2781     case ResumeMode::IMMEDIATE_RESTART:
2782       return "IMMEDIATE_RESTART";
2783     case ResumeMode::USER_CONTINUE:
2784       return "USER_CONTINUE";
2785     case ResumeMode::USER_RESTART:
2786       return "USER_RESTART";
2787   }
2788   NOTREACHED() << "Unknown resume mode " << static_cast<int>(mode);
2789   return "unknown";
2790 }
2791 
GetApproximateMemoryUsage() const2792 size_t DownloadItemImpl::GetApproximateMemoryUsage() const {
2793   static size_t class_size = sizeof(DownloadItemImpl);
2794   size_t size = class_size;
2795 
2796   for (const GURL& url : GetUrlChain())
2797     size += url.EstimateMemoryUsage();
2798   size += GetReferrerUrl().EstimateMemoryUsage();
2799   size += GetSiteUrl().EstimateMemoryUsage();
2800   size += GetTabUrl().EstimateMemoryUsage();
2801   size += GetTabReferrerUrl().EstimateMemoryUsage();
2802   size += base::trace_event::EstimateMemoryUsage(GetSuggestedFilename());
2803   size += base::trace_event::EstimateMemoryUsage(GetForcedFilePath().value());
2804   size += base::trace_event::EstimateMemoryUsage(GetRemoteAddress());
2805   size += base::trace_event::EstimateMemoryUsage(GetTargetFilePath().value());
2806   size += base::trace_event::EstimateMemoryUsage(GetFullPath().value());
2807   size += base::trace_event::EstimateMemoryUsage(GetHash());
2808   size += base::trace_event::EstimateMemoryUsage(GetMimeType());
2809   size += base::trace_event::EstimateMemoryUsage(GetOriginalMimeType());
2810   size += base::trace_event::EstimateMemoryUsage(GetLastModifiedTime());
2811   size += base::trace_event::EstimateMemoryUsage(GetETag());
2812   size += base::trace_event::EstimateMemoryUsage(GetGuid());
2813   return size;
2814 }
2815 
2816 }  // namespace download
2817