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