Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: content/browser/download/download_item_impl.cc

Issue 1691543002: [Downloads] Enforce state transition integrity and state invariants. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Clarify comments. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // File method ordering: Methods in this file are in the same order as 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 6 // in download_item_impl.h, with the following exception: The public
7 // interface Start is placed in chronological order with the other 7 // interface Start is placed in chronological order with the other
8 // (private) routines that together define a DownloadItem's state 8 // (private) routines that together define a DownloadItem's state
9 // transitions as the download progresses. See "Download progression 9 // transitions as the download progresses. See "Download progression
10 // cascade" later in this file. 10 // cascade" later in this file.
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 file_externally_removed_(false), 153 file_externally_removed_(false),
154 auto_opened_(false), 154 auto_opened_(false),
155 is_temporary_(false), 155 is_temporary_(false),
156 all_data_saved_(state == COMPLETE), 156 all_data_saved_(state == COMPLETE),
157 destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE), 157 destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
158 opened_(opened), 158 opened_(opened),
159 delegate_delayed_complete_(false), 159 delegate_delayed_complete_(false),
160 bound_net_log_(bound_net_log), 160 bound_net_log_(bound_net_log),
161 weak_ptr_factory_(this) { 161 weak_ptr_factory_(this) {
162 delegate_->Attach(); 162 delegate_->Attach();
163 DCHECK_NE(IN_PROGRESS_INTERNAL, state_); 163 DCHECK(state_ == COMPLETE_INTERNAL || state_ == INTERRUPTED_INTERNAL ||
164 state_ == CANCELLED_INTERNAL);
164 Init(false /* not actively downloading */, SRC_HISTORY_IMPORT); 165 Init(false /* not actively downloading */, SRC_HISTORY_IMPORT);
165 } 166 }
166 167
167 // Constructing for a regular download: 168 // Constructing for a regular download:
168 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, 169 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
169 uint32_t download_id, 170 uint32_t download_id,
170 const DownloadCreateInfo& info, 171 const DownloadCreateInfo& info,
171 const net::BoundNetLog& bound_net_log) 172 const net::BoundNetLog& bound_net_log)
172 : is_save_package_download_(false), 173 : is_save_package_download_(false),
173 download_id_(download_id), 174 download_id_(download_id),
(...skipping 12 matching lines...) Expand all
186 mime_type_(info.mime_type), 187 mime_type_(info.mime_type),
187 original_mime_type_(info.original_mime_type), 188 original_mime_type_(info.original_mime_type),
188 remote_address_(info.remote_address), 189 remote_address_(info.remote_address),
189 total_bytes_(info.total_bytes), 190 total_bytes_(info.total_bytes),
190 received_bytes_(0), 191 received_bytes_(0),
191 bytes_per_sec_(0), 192 bytes_per_sec_(0),
192 last_modified_time_(info.last_modified), 193 last_modified_time_(info.last_modified),
193 etag_(info.etag), 194 etag_(info.etag),
194 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE), 195 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
195 start_tick_(base::TimeTicks::Now()), 196 start_tick_(base::TimeTicks::Now()),
196 state_(IN_PROGRESS_INTERNAL), 197 state_(INITIAL_INTERNAL),
197 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), 198 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
198 start_time_(info.start_time), 199 start_time_(info.start_time),
199 delegate_(delegate), 200 delegate_(delegate),
200 is_paused_(false), 201 is_paused_(false),
201 auto_resume_count_(0), 202 auto_resume_count_(0),
202 open_when_complete_(false), 203 open_when_complete_(false),
203 file_externally_removed_(false), 204 file_externally_removed_(false),
204 auto_opened_(false), 205 auto_opened_(false),
205 is_temporary_(!info.save_info->file_path.empty()), 206 is_temporary_(!info.save_info->file_path.empty()),
206 all_data_saved_(false), 207 all_data_saved_(false),
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 UpdateObservers(); 321 UpdateObservers();
321 322
322 MaybeCompleteDownload(); 323 MaybeCompleteDownload();
323 } 324 }
324 325
325 void DownloadItemImpl::StealDangerousDownload( 326 void DownloadItemImpl::StealDangerousDownload(
326 const AcquireFileCallback& callback) { 327 const AcquireFileCallback& callback) {
327 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); 328 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
328 DCHECK_CURRENTLY_ON(BrowserThread::UI); 329 DCHECK_CURRENTLY_ON(BrowserThread::UI);
329 DCHECK(IsDangerous()); 330 DCHECK(IsDangerous());
331
330 if (download_file_) { 332 if (download_file_) {
331 BrowserThread::PostTaskAndReplyWithResult( 333 BrowserThread::PostTaskAndReplyWithResult(
332 BrowserThread::FILE, 334 BrowserThread::FILE,
333 FROM_HERE, 335 FROM_HERE,
334 base::Bind(&DownloadFileDetach, base::Passed(&download_file_)), 336 base::Bind(&DownloadFileDetach, base::Passed(&download_file_)),
335 callback); 337 callback);
336 } else { 338 } else {
337 callback.Run(current_path_); 339 callback.Run(current_path_);
338 } 340 }
339 current_path_.clear(); 341 current_path_.clear();
340 Remove(); 342 Remove();
341 // We have now been deleted. 343 // We have now been deleted.
342 } 344 }
343 345
344 void DownloadItemImpl::Pause() { 346 void DownloadItemImpl::Pause() {
345 DCHECK_CURRENTLY_ON(BrowserThread::UI); 347 DCHECK_CURRENTLY_ON(BrowserThread::UI);
346 348
347 // Ignore irrelevant states. 349 // Ignore irrelevant states.
348 if (state_ != IN_PROGRESS_INTERNAL || is_paused_) 350 if (is_paused_)
349 return; 351 return;
350 352
351 request_handle_->PauseRequest(); 353 switch (state_) {
352 is_paused_ = true; 354 case INITIAL_INTERNAL:
353 UpdateObservers(); 355 case COMPLETING_INTERNAL:
356 case COMPLETE_INTERNAL:
357 case INTERRUPTED_INTERNAL:
358 case CANCELLED_INTERNAL:
359 case RESUMING_INTERNAL:
360 // No active request.
361 return;
362
363 case TARGET_PENDING_INTERNAL:
364 case TARGET_RESOLVED_INTERNAL:
365 case IN_PROGRESS_INTERNAL:
366 request_handle_->PauseRequest();
367 is_paused_ = true;
368 UpdateObservers();
369 return;
370
371 case MAX_DOWNLOAD_INTERNAL_STATE:
372 NOTREACHED();
373 }
354 } 374 }
355 375
356 void DownloadItemImpl::Resume() { 376 void DownloadItemImpl::Resume() {
357 DCHECK_CURRENTLY_ON(BrowserThread::UI); 377 DCHECK_CURRENTLY_ON(BrowserThread::UI);
358 switch (state_) { 378 switch (state_) {
379 case INITIAL_INTERNAL:
380 case COMPLETING_INTERNAL:
381 case COMPLETE_INTERNAL:
382 case CANCELLED_INTERNAL:
383 // Nothing to resume.
384 case RESUMING_INTERNAL:
385 // Resumption in progress.
386 return;
Randy Smith (Not in Mondays) 2016/02/12 00:03:11 suggestion: DCHECK(!is_paused_)?
asanka 2016/02/12 05:04:26 Done.
387
388 case TARGET_PENDING_INTERNAL:
389 case TARGET_RESOLVED_INTERNAL:
359 case IN_PROGRESS_INTERNAL: 390 case IN_PROGRESS_INTERNAL:
360 if (!is_paused_) 391 if (!is_paused_)
361 return; 392 return;
362 request_handle_->ResumeRequest(); 393 request_handle_->ResumeRequest();
363 is_paused_ = false; 394 is_paused_ = false;
364 UpdateObservers(); 395 UpdateObservers();
365 return; 396 return;
366 397
367 case COMPLETING_INTERNAL:
368 case COMPLETE_INTERNAL:
369 case CANCELLED_INTERNAL:
370 case RESUMING_INTERNAL:
371 return;
372
373 case INTERRUPTED_INTERNAL: 398 case INTERRUPTED_INTERNAL:
374 auto_resume_count_ = 0; // User input resets the counter. 399 auto_resume_count_ = 0; // User input resets the counter.
375 ResumeInterruptedDownload(); 400 ResumeInterruptedDownload();
376 return; 401 return;
377 402
378 case MAX_DOWNLOAD_INTERNAL_STATE: 403 case MAX_DOWNLOAD_INTERNAL_STATE:
379 NOTREACHED(); 404 NOTREACHED();
380 } 405 }
381 } 406 }
382 407
383 void DownloadItemImpl::Cancel(bool user_cancel) { 408 void DownloadItemImpl::Cancel(bool user_cancel) {
384 DCHECK_CURRENTLY_ON(BrowserThread::UI); 409 DCHECK_CURRENTLY_ON(BrowserThread::UI);
385
386 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); 410 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
387 if (state_ != IN_PROGRESS_INTERNAL && 411 Interrupt(user_cancel ? DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
388 state_ != INTERRUPTED_INTERNAL && 412 : DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN);
389 state_ != RESUMING_INTERNAL) {
390 // Small downloads might be complete before this method has a chance to run.
391 return;
392 }
393
394 if (IsDangerous()) {
395 RecordDangerousDownloadDiscard(
396 user_cancel ? DOWNLOAD_DISCARD_DUE_TO_USER_ACTION
397 : DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN,
398 GetDangerType(),
399 GetTargetFilePath());
400 }
401
402 last_reason_ = user_cancel ? DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
403 : DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
404
405 RecordDownloadCount(CANCELLED_COUNT);
406
407 // TODO(rdsmith/benjhayden): Remove condition as part of
408 // |SavePackage| integration.
409 // |download_file_| can be NULL if Interrupt() is called after the
410 // download file has been released.
411 if (!is_save_package_download_ && download_file_)
Randy Smith (Not in Mondays) 2016/02/12 00:03:11 Interesting. Was the is_save_package_download_ ch
asanka 2016/02/12 05:04:26 It was cleanup. I don't know why it was there eith
412 ReleaseDownloadFile(true);
413
414 if (state_ == IN_PROGRESS_INTERNAL) {
415 // Cancel the originating URL request unless it's already been cancelled
416 // by interrupt.
417 request_handle_->CancelRequest();
418 }
419
420 // Remove the intermediate file if we are cancelling an interrupted download.
421 // Continuable interruptions leave the intermediate file around.
422 if ((state_ == INTERRUPTED_INTERNAL || state_ == RESUMING_INTERNAL) &&
423 !current_path_.empty()) {
424 BrowserThread::PostTask(
425 BrowserThread::FILE, FROM_HERE,
426 base::Bind(base::IgnoreResult(&DeleteDownloadedFile), current_path_));
427 current_path_.clear();
428 }
429
430 TransitionTo(CANCELLED_INTERNAL, UPDATE_OBSERVERS);
431 } 413 }
432 414
433 void DownloadItemImpl::Remove() { 415 void DownloadItemImpl::Remove() {
434 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); 416 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
435 DCHECK_CURRENTLY_ON(BrowserThread::UI); 417 DCHECK_CURRENTLY_ON(BrowserThread::UI);
436 418
437 delegate_->AssertStateConsistent(this); 419 delegate_->AssertStateConsistent(this);
438 Cancel(true); 420 Interrupt(DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
439 delegate_->AssertStateConsistent(this); 421 delegate_->AssertStateConsistent(this);
440 422
441 NotifyRemoved(); 423 NotifyRemoved();
442 delegate_->DownloadRemoved(this); 424 delegate_->DownloadRemoved(this);
443 // We have now been deleted. 425 // We have now been deleted.
444 } 426 }
445 427
446 void DownloadItemImpl::OpenDownload() { 428 void DownloadItemImpl::OpenDownload() {
447 DCHECK_CURRENTLY_ON(BrowserThread::UI); 429 DCHECK_CURRENTLY_ON(BrowserThread::UI);
448 430
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 470
489 bool DownloadItemImpl::IsPaused() const { 471 bool DownloadItemImpl::IsPaused() const {
490 return is_paused_; 472 return is_paused_;
491 } 473 }
492 474
493 bool DownloadItemImpl::IsTemporary() const { 475 bool DownloadItemImpl::IsTemporary() const {
494 return is_temporary_; 476 return is_temporary_;
495 } 477 }
496 478
497 bool DownloadItemImpl::CanResume() const { 479 bool DownloadItemImpl::CanResume() const {
498 if ((GetState() == IN_PROGRESS) && IsPaused()) 480 DCHECK_CURRENTLY_ON(BrowserThread::UI);
499 return true; 481 switch (state_) {
482 case INITIAL_INTERNAL:
483 case COMPLETING_INTERNAL:
484 case COMPLETE_INTERNAL:
485 case CANCELLED_INTERNAL:
486 case RESUMING_INTERNAL:
487 return false;
500 488
501 if (state_ != INTERRUPTED_INTERNAL) 489 case TARGET_PENDING_INTERNAL:
502 return false; 490 case TARGET_RESOLVED_INTERNAL:
491 case IN_PROGRESS_INTERNAL:
492 return is_paused_;
503 493
504 // We currently only support HTTP(S) requests for download resumption. 494 case INTERRUPTED_INTERNAL: {
505 if (!GetURL().SchemeIsHTTPOrHTTPS()) 495 ResumeMode resume_mode = GetResumeMode();
506 return false; 496 // Only allow Resume() calls if the resumption mode requires a user
497 // action.
498 return IsDownloadResumptionEnabled() &&
499 (resume_mode == RESUME_MODE_USER_RESTART ||
500 resume_mode == RESUME_MODE_USER_CONTINUE);
501 }
507 502
508 ResumeMode resume_mode = GetResumeMode(); 503 case MAX_DOWNLOAD_INTERNAL_STATE:
509 return IsDownloadResumptionEnabled() && 504 NOTREACHED();
510 (resume_mode == RESUME_MODE_USER_RESTART || 505 }
511 resume_mode == RESUME_MODE_USER_CONTINUE); 506 return false;
512 } 507 }
513 508
514 bool DownloadItemImpl::IsDone() const { 509 bool DownloadItemImpl::IsDone() const {
515 switch (state_) { 510 switch (state_) {
511 case INITIAL_INTERNAL:
512 case COMPLETING_INTERNAL:
Randy Smith (Not in Mondays) 2016/02/12 00:03:11 Not in this CL (as not changed in this CL): I find
asanka 2016/02/12 05:04:26 Acknowledged.
513 case RESUMING_INTERNAL:
514 case TARGET_PENDING_INTERNAL:
515 case TARGET_RESOLVED_INTERNAL:
516 case IN_PROGRESS_INTERNAL: 516 case IN_PROGRESS_INTERNAL:
517 case COMPLETING_INTERNAL:
518 return false; 517 return false;
519 518
520 case COMPLETE_INTERNAL: 519 case COMPLETE_INTERNAL:
521 case CANCELLED_INTERNAL: 520 case CANCELLED_INTERNAL:
522 return true; 521 return true;
523 522
524 case INTERRUPTED_INTERNAL: 523 case INTERRUPTED_INTERNAL:
525 return !CanResume(); 524 return !CanResume();
526 525
527 case RESUMING_INTERNAL:
528 return false;
529
530 case MAX_DOWNLOAD_INTERNAL_STATE: 526 case MAX_DOWNLOAD_INTERNAL_STATE:
531 break; 527 NOTREACHED();
532 } 528 }
533 NOTREACHED(); 529 return false;
534 return true;
535 } 530 }
536 531
537 const GURL& DownloadItemImpl::GetURL() const { 532 const GURL& DownloadItemImpl::GetURL() const {
538 return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.back(); 533 return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.back();
539 } 534 }
540 535
541 const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const { 536 const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const {
542 return url_chain_; 537 return url_chain_;
543 } 538 }
544 539
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 // Currently such items have null request_handle_s, where other items 758 // Currently such items have null request_handle_s, where other items
764 // (regular and SavePackage downloads) have actual objects off the pointer. 759 // (regular and SavePackage downloads) have actual objects off the pointer.
765 if (request_handle_) 760 if (request_handle_)
766 return request_handle_->GetWebContents(); 761 return request_handle_->GetWebContents();
767 return NULL; 762 return NULL;
768 } 763 }
769 764
770 void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type) { 765 void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type) {
771 DCHECK_CURRENTLY_ON(BrowserThread::UI); 766 DCHECK_CURRENTLY_ON(BrowserThread::UI);
772 DCHECK(AllDataSaved()); 767 DCHECK(AllDataSaved());
768
769 // Danger type is only allowed to be set on an active download after all data
770 // has been saved. This excludes all other states. In particular,
771 // OnContentCheckCompleted() isn't allowed on an INTERRUPTED download since
772 // such an interruption would need to happen between OnAllDataSaved() and
773 // OnContentCheckCompleted() during which no disk or network activity
774 // should've taken place.
775 DCHECK_EQ(state_, IN_PROGRESS_INTERNAL);
773 DVLOG(20) << __FUNCTION__ << " danger_type=" << danger_type 776 DVLOG(20) << __FUNCTION__ << " danger_type=" << danger_type
774 << " download=" << DebugString(true); 777 << " download=" << DebugString(true);
775 SetDangerType(danger_type); 778 SetDangerType(danger_type);
776 UpdateObservers(); 779 UpdateObservers();
777 } 780 }
778 781
779 void DownloadItemImpl::SetOpenWhenComplete(bool open) { 782 void DownloadItemImpl::SetOpenWhenComplete(bool open) {
780 open_when_complete_ = open; 783 open_when_complete_ = open;
781 } 784 }
782 785
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
847 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); 850 description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
848 } 851 }
849 852
850 description += " }"; 853 description += " }";
851 854
852 return description; 855 return description;
853 } 856 }
854 857
855 DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const { 858 DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
856 DCHECK_CURRENTLY_ON(BrowserThread::UI); 859 DCHECK_CURRENTLY_ON(BrowserThread::UI);
860
861 if (!IsDownloadResumptionEnabled())
862 return RESUME_MODE_INVALID;
863
864 // Cnly support resumption for HTTP(S).
Randy Smith (Not in Mondays) 2016/02/12 00:03:10 Interesting. This seems like a semantic change th
asanka 2016/02/12 05:04:26 I moved this check from CanResume() to here. Earli
865 if (!GetURL().SchemeIsHTTPOrHTTPS())
866 return RESUME_MODE_INVALID;
867
857 // We can't continue without a handle on the intermediate file. 868 // We can't continue without a handle on the intermediate file.
858 // We also can't continue if we don't have some verifier to make sure 869 // We also can't continue if we don't have some verifier to make sure
859 // we're getting the same file. 870 // we're getting the same file.
860 const bool force_restart = 871 const bool force_restart =
861 (current_path_.empty() || (etag_.empty() && last_modified_time_.empty())); 872 (current_path_.empty() || (etag_.empty() && last_modified_time_.empty()));
862 873
863 // We won't auto-restart if we've used up our attempts or the 874 // We won't auto-restart if we've used up our attempts or the
864 // download has been paused by user action. 875 // download has been paused by user action.
865 const bool force_user = 876 const bool force_user =
866 (auto_resume_count_ >= kMaxAutoResumeAttempts || is_paused_); 877 (auto_resume_count_ >= kMaxAutoResumeAttempts || is_paused_);
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
987 const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const { 998 const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
988 return bound_net_log_; 999 return bound_net_log_;
989 } 1000 }
990 1001
991 void DownloadItemImpl::SetTotalBytes(int64_t total_bytes) { 1002 void DownloadItemImpl::SetTotalBytes(int64_t total_bytes) {
992 total_bytes_ = total_bytes; 1003 total_bytes_ = total_bytes;
993 } 1004 }
994 1005
995 void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) { 1006 void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
996 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1007 DCHECK_CURRENTLY_ON(BrowserThread::UI);
997 1008 DCHECK(state_ == TARGET_PENDING_INTERNAL ||
998 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_); 1009 state_ == TARGET_RESOLVED_INTERNAL || state_ == IN_PROGRESS_INTERNAL);
Randy Smith (Not in Mondays) 2016/02/12 00:03:10 DestinationCompleted comes in via post from the fi
asanka 2016/02/12 05:04:26 This one is a bit subtle. Basically, if the DII tr
Randy Smith (Not in Mondays) 2016/02/12 17:37:02 Ah, thank you. However, as I read the code, what
asanka 2016/02/12 20:21:24 Yeah. We rely on download_file_ only being set to
999 DCHECK(!all_data_saved_); 1010 DCHECK(!all_data_saved_);
1000 all_data_saved_ = true; 1011 all_data_saved_ = true;
1001 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); 1012 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
1002 1013
1003 // Store final hash and null out intermediate serialized hash state. 1014 // Store final hash and null out intermediate serialized hash state.
1004 hash_ = final_hash; 1015 hash_ = final_hash;
1005 hash_state_ = ""; 1016 hash_state_ = "";
1006 1017
1007 UpdateObservers(); 1018 UpdateObservers();
1008 } 1019 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1047 if (bound_net_log_.IsCapturing()) { 1058 if (bound_net_log_.IsCapturing()) {
1048 bound_net_log_.AddEvent( 1059 bound_net_log_.AddEvent(
1049 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED, 1060 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
1050 net::NetLog::Int64Callback("bytes_so_far", received_bytes_)); 1061 net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
1051 } 1062 }
1052 1063
1053 UpdateObservers(); 1064 UpdateObservers();
1054 } 1065 }
1055 1066
1056 void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) { 1067 void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) {
1068 DCHECK(state_ == TARGET_PENDING_INTERNAL ||
1069 state_ == TARGET_RESOLVED_INTERNAL || state_ == IN_PROGRESS_INTERNAL);
1070 DVLOG(20) << __FUNCTION__
1071 << "() reason:" << DownloadInterruptReasonToString(reason);
1072
1057 // Postpone recognition of this error until after file name determination 1073 // Postpone recognition of this error until after file name determination
1058 // has completed and the intermediate file has been renamed to simplify 1074 // has completed and the intermediate file has been renamed to simplify
1059 // resumption conditions. 1075 // resumption conditions.
1060 if (current_path_.empty() || target_path_.empty()) 1076 if (state_ != IN_PROGRESS_INTERNAL)
Randy Smith (Not in Mondays) 2016/02/12 00:03:11 Confirming I understand (if this is true, I'm ok w
asanka 2016/02/12 05:04:26 Correct.
1061 destination_error_ = reason; 1077 destination_error_ = reason;
1062 else 1078 else
1063 Interrupt(reason); 1079 Interrupt(reason);
1064 } 1080 }
1065 1081
1066 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) { 1082 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
1067 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); 1083 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
1068 if (GetState() != IN_PROGRESS)
1069 return;
1070 OnAllDataSaved(final_hash); 1084 OnAllDataSaved(final_hash);
1071 MaybeCompleteDownload(); 1085 MaybeCompleteDownload();
1072 } 1086 }
1073 1087
1074 // **** Download progression cascade 1088 // **** Download progression cascade
1075 1089
1076 void DownloadItemImpl::Init(bool active, 1090 void DownloadItemImpl::Init(bool active,
1077 DownloadType download_type) { 1091 DownloadType download_type) {
1078 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1092 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1079 1093
(...skipping 29 matching lines...) Expand all
1109 } 1123 }
1110 1124
1111 // We're starting the download. 1125 // We're starting the download.
1112 void DownloadItemImpl::Start( 1126 void DownloadItemImpl::Start(
1113 scoped_ptr<DownloadFile> file, 1127 scoped_ptr<DownloadFile> file,
1114 scoped_ptr<DownloadRequestHandleInterface> req_handle) { 1128 scoped_ptr<DownloadRequestHandleInterface> req_handle) {
1115 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1129 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1116 DCHECK(!download_file_.get()); 1130 DCHECK(!download_file_.get());
1117 DCHECK(file.get()); 1131 DCHECK(file.get());
1118 DCHECK(req_handle.get()); 1132 DCHECK(req_handle.get());
1133 DVLOG(20) << __FUNCTION__ << "() this=" << DebugString(true);
1119 1134
1120 download_file_ = std::move(file); 1135 download_file_ = std::move(file);
1121 request_handle_ = std::move(req_handle); 1136 request_handle_ = std::move(req_handle);
1122 1137
1123 if (GetState() == CANCELLED) { 1138 if (state_ == CANCELLED_INTERNAL) {
1124 // The download was in the process of resuming when it was cancelled. Don't 1139 // The download was in the process of resuming when it was cancelled. Don't
1125 // proceed. 1140 // proceed.
1126 ReleaseDownloadFile(true); 1141 ReleaseDownloadFile(true);
1127 request_handle_->CancelRequest(); 1142 request_handle_->CancelRequest();
1128 return; 1143 return;
1129 } 1144 }
1130 1145
1131 TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS); 1146 TransitionTo(TARGET_PENDING_INTERNAL, UPDATE_OBSERVERS);
1132 1147
1133 BrowserThread::PostTask( 1148 BrowserThread::PostTask(
1134 BrowserThread::FILE, FROM_HERE, 1149 BrowserThread::FILE, FROM_HERE,
1135 base::Bind(&DownloadFile::Initialize, 1150 base::Bind(&DownloadFile::Initialize,
1136 // Safe because we control download file lifetime. 1151 // Safe because we control download file lifetime.
1137 base::Unretained(download_file_.get()), 1152 base::Unretained(download_file_.get()),
1138 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, 1153 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
1139 weak_ptr_factory_.GetWeakPtr()))); 1154 weak_ptr_factory_.GetWeakPtr())));
1140 } 1155 }
1141 1156
1142 void DownloadItemImpl::OnDownloadFileInitialized( 1157 void DownloadItemImpl::OnDownloadFileInitialized(
1143 DownloadInterruptReason result) { 1158 DownloadInterruptReason result) {
1144 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1159 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1160 DCHECK_EQ(state_, TARGET_PENDING_INTERNAL);
1161 DVLOG(20) << __FUNCTION__
1162 << "() result:" << DownloadInterruptReasonToString(result);
1145 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) { 1163 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
1164 // Transition out to TARGET_RESOLVED_INTERNAL since this DownloadItem is
1165 // skipping the download target determination process.
1166 TransitionTo(TARGET_RESOLVED_INTERNAL, DONT_UPDATE_OBSERVERS);
1146 Interrupt(result); 1167 Interrupt(result);
1147 // TODO(rdsmith/asanka): Arguably we should show this in the UI, but 1168 // TODO(rdsmith/asanka): Arguably we should show this in the UI, but
1148 // it's not at all clear what to show--we haven't done filename 1169 // it's not at all clear what to show--we haven't done filename
1149 // determination, so we don't know what name to display. OTOH, 1170 // determination, so we don't know what name to display. OTOH,
1150 // the failure mode of not showing the DI if the file initialization 1171 // the failure mode of not showing the DI if the file initialization
1151 // fails isn't a good one. Can we hack up a name based on the 1172 // fails isn't a good one. Can we hack up a name based on the
1152 // URLRequest? We'll need to make sure that initialization happens 1173 // URLRequest? We'll need to make sure that initialization happens
1153 // properly. Possibly the right thing is to have the UI handle 1174 // properly. Possibly the right thing is to have the UI handle
1154 // this case specially. 1175 // this case specially.
1155 return; 1176 return;
1156 } 1177 }
1157 1178
1158 delegate_->DetermineDownloadTarget( 1179 delegate_->DetermineDownloadTarget(
1159 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined, 1180 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
1160 weak_ptr_factory_.GetWeakPtr())); 1181 weak_ptr_factory_.GetWeakPtr()));
1161 } 1182 }
1162 1183
1163 // Called by delegate_ when the download target path has been 1184 // Called by delegate_ when the download target path has been
1164 // determined. 1185 // determined.
1165 void DownloadItemImpl::OnDownloadTargetDetermined( 1186 void DownloadItemImpl::OnDownloadTargetDetermined(
1166 const base::FilePath& target_path, 1187 const base::FilePath& target_path,
1167 TargetDisposition disposition, 1188 TargetDisposition disposition,
1168 DownloadDangerType danger_type, 1189 DownloadDangerType danger_type,
1169 const base::FilePath& intermediate_path) { 1190 const base::FilePath& intermediate_path) {
1170 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1191 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1192 DCHECK_EQ(state_, TARGET_PENDING_INTERNAL);
1171 1193
1172 // If the |target_path| is empty, then we consider this download to be 1194 // If the |target_path| is empty, then we consider this download to be
1173 // canceled. 1195 // canceled.
1174 if (target_path.empty()) { 1196 if (target_path.empty()) {
1175 Cancel(true); 1197 Cancel(true);
1176 return; 1198 return;
1177 } 1199 }
1178 1200
1179 // TODO(rdsmith,asanka): We are ignoring the possibility that the download 1201 // TODO(rdsmith,asanka): We are ignoring the possibility that the download
1180 // has been interrupted at this point until we finish the intermediate 1202 // has been interrupted at this point until we finish the intermediate
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1224 base::Bind(&DownloadFile::RenameAndUniquify, 1246 base::Bind(&DownloadFile::RenameAndUniquify,
1225 // Safe because we control download file lifetime. 1247 // Safe because we control download file lifetime.
1226 base::Unretained(download_file_.get()), 1248 base::Unretained(download_file_.get()),
1227 intermediate_path, callback)); 1249 intermediate_path, callback));
1228 } 1250 }
1229 1251
1230 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( 1252 void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
1231 DownloadInterruptReason reason, 1253 DownloadInterruptReason reason,
1232 const base::FilePath& full_path) { 1254 const base::FilePath& full_path) {
1233 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1255 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1256 DCHECK_EQ(state_, TARGET_PENDING_INTERNAL);
1234 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); 1257 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
1258 TransitionTo(TARGET_RESOLVED_INTERNAL, DONT_UPDATE_OBSERVERS);
1235 1259
1236 if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) { 1260 if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) {
1237 // Process destination error. If both |reason| and |destination_error_| 1261 // Process destination error. If both |reason| and |destination_error_|
1238 // refer to actual errors, we want to use the |destination_error_| as the 1262 // refer to actual errors, we want to use the |destination_error_| as the
1239 // argument to the Interrupt() routine, as it happened first. 1263 // argument to the Interrupt() routine, as it happened first.
1240 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) 1264 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE)
1241 SetFullPath(full_path); 1265 SetFullPath(full_path);
1242 Interrupt(destination_error_); 1266 Interrupt(destination_error_);
1243 destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE; 1267 destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
1244 } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { 1268 } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
1245 Interrupt(reason); 1269 Interrupt(reason);
1246 // All file errors result in file deletion above; no need to cleanup. The 1270 // All file errors result in file deletion above; no need to cleanup. The
1247 // current_path_ should be empty. Resuming this download will force a 1271 // current_path_ should be empty. Resuming this download will force a
1248 // restart and a re-doing of filename determination. 1272 // restart and a re-doing of filename determination.
1249 DCHECK(current_path_.empty()); 1273 DCHECK(current_path_.empty());
1250 } else { 1274 } else {
1251 SetFullPath(full_path); 1275 SetFullPath(full_path);
1252 UpdateObservers(); 1276 TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS);
1253 MaybeCompleteDownload(); 1277 MaybeCompleteDownload();
1254 } 1278 }
1255 } 1279 }
1256 1280
1257 // When SavePackage downloads MHTML to GData (see 1281 // When SavePackage downloads MHTML to GData (see
1258 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it 1282 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
1259 // does for non-SavePackage downloads, but SavePackage downloads never satisfy 1283 // does for non-SavePackage downloads, but SavePackage downloads never satisfy
1260 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls 1284 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
1261 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage 1285 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage
1262 // notices that the upload has completed and runs its normal Finish() pathway. 1286 // notices that the upload has completed and runs its normal Finish() pathway.
1263 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes 1287 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes
1264 // downloads. SavePackage always uses its own Finish() to mark downloads 1288 // downloads. SavePackage always uses its own Finish() to mark downloads
1265 // complete. 1289 // complete.
1266 void DownloadItemImpl::MaybeCompleteDownload() { 1290 void DownloadItemImpl::MaybeCompleteDownload() {
1267 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1291 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1268 DCHECK(!is_save_package_download_); 1292 DCHECK(!is_save_package_download_);
1269 1293
1270 if (!IsDownloadReadyForCompletion( 1294 if (!IsDownloadReadyForCompletion(
1271 base::Bind(&DownloadItemImpl::MaybeCompleteDownload, 1295 base::Bind(&DownloadItemImpl::MaybeCompleteDownload,
1272 weak_ptr_factory_.GetWeakPtr()))) 1296 weak_ptr_factory_.GetWeakPtr())))
1273 return; 1297 return;
1274 1298
1275 // TODO(rdsmith): DCHECK that we only pass through this point 1299 // Confirm we're in the proper set of states to be here; have all data, have a
1276 // once per download. The natural way to do this is by a state 1300 // history handle, (validated or safe).
1277 // transition on the DownloadItem.
1278
1279 // Confirm we're in the proper set of states to be here;
1280 // have all data, have a history handle, (validated or safe).
1281 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_); 1301 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
1282 DCHECK(!IsDangerous()); 1302 DCHECK(!IsDangerous());
1283 DCHECK(all_data_saved_); 1303 DCHECK(all_data_saved_);
1284 1304
1285 OnDownloadCompleting(); 1305 OnDownloadCompleting();
1286 } 1306 }
1287 1307
1288 // Called by MaybeCompleteDownload() when it has determined that the download 1308 // Called by MaybeCompleteDownload() when it has determined that the download
1289 // is ready for completion. 1309 // is ready for completion.
1290 void DownloadItemImpl::OnDownloadCompleting() { 1310 void DownloadItemImpl::OnDownloadCompleting() {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1349 1369
1350 DCHECK(target_path_ == full_path); 1370 DCHECK(target_path_ == full_path);
1351 1371
1352 if (full_path != current_path_) { 1372 if (full_path != current_path_) {
1353 // full_path is now the current and target file path. 1373 // full_path is now the current and target file path.
1354 DCHECK(!full_path.empty()); 1374 DCHECK(!full_path.empty());
1355 SetFullPath(full_path); 1375 SetFullPath(full_path);
1356 } 1376 }
1357 1377
1358 // Complete the download and release the DownloadFile. 1378 // Complete the download and release the DownloadFile.
1359 DCHECK(download_file_.get()); 1379 DCHECK(download_file_);
1360 ReleaseDownloadFile(false); 1380 ReleaseDownloadFile(false);
1361 1381
1362 // We're not completely done with the download item yet, but at this 1382 // We're not completely done with the download item yet, but at this
1363 // point we're committed to complete the download. Cancels (or Interrupts, 1383 // point we're committed to complete the download. Cancels (or Interrupts,
1364 // though it's not clear how they could happen) after this point will be 1384 // though it's not clear how they could happen) after this point will be
1365 // ignored. 1385 // ignored.
1366 TransitionTo(COMPLETING_INTERNAL, DONT_UPDATE_OBSERVERS); 1386 TransitionTo(COMPLETING_INTERNAL, DONT_UPDATE_OBSERVERS);
1367 1387
1368 if (delegate_->ShouldOpenDownload( 1388 if (delegate_->ShouldOpenDownload(
1369 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened, 1389 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened,
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
1423 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); 1443 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
1424 Interrupt(interrupt_reason); 1444 Interrupt(interrupt_reason);
1425 } 1445 }
1426 1446
1427 // **** End of Download progression cascade 1447 // **** End of Download progression cascade
1428 1448
1429 // An error occurred somewhere. 1449 // An error occurred somewhere.
1430 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { 1450 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
1431 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1451 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1432 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason); 1452 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason);
1453 DVLOG(20) << __FUNCTION__
1454 << "() reason:" << DownloadInterruptReasonToString(reason)
1455 << " this=" << DebugString(true);
1433 1456
1434 // Somewhat counter-intuitively, it is possible for us to receive an 1457 // Somewhat counter-intuitively, it is possible for us to receive an
1435 // interrupt after we've already been interrupted. The generation of 1458 // interrupt after we've already been interrupted. The generation of
1436 // interrupts from the file thread Renames and the generation of 1459 // interrupts from the file thread Renames and the generation of
1437 // interrupts from disk writes go through two different mechanisms (driven 1460 // interrupts from disk writes go through two different mechanisms (driven
1438 // by rename requests from UI thread and by write requests from IO thread, 1461 // by rename requests from UI thread and by write requests from IO thread,
1439 // respectively), and since we choose not to keep state on the File thread, 1462 // respectively), and since we choose not to keep state on the File thread,
1440 // this is the place where the races collide. It's also possible for 1463 // this is the place where the races collide. It's also possible for
1441 // interrupts to race with cancels. 1464 // interrupts to race with cancels.
1465 switch (state_) {
1466 case CANCELLED_INTERNAL:
1467 // If the download is already cancelled, then there's no point in
1468 // transitioning out to interrupted.
1469 case COMPLETING_INTERNAL:
1470 case COMPLETE_INTERNAL:
1471 // Already complete.
1472 return;
1442 1473
1443 // Whatever happens, the first one to hit the UI thread wins. 1474 case TARGET_PENDING_INTERNAL:
1444 if (state_ != IN_PROGRESS_INTERNAL && state_ != RESUMING_INTERNAL) 1475 case TARGET_RESOLVED_INTERNAL:
1445 return; 1476 case IN_PROGRESS_INTERNAL:
1477 break;
1478
1479 case RESUMING_INTERNAL:
1480 case INTERRUPTED_INTERNAL:
1481 // The first non-cancel interrupt reason wins in cases where multiple
1482 // things go wrong.
1483 if (reason != DOWNLOAD_INTERRUPT_REASON_USER_CANCELED &&
1484 reason != DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN)
1485 return;
1486
1487 if (!current_path_.empty()) {
1488 BrowserThread::PostTask(
1489 BrowserThread::FILE, FROM_HERE,
1490 base::Bind(base::IgnoreResult(&DeleteDownloadedFile),
1491 current_path_));
1492 current_path_.clear();
Randy Smith (Not in Mondays) 2016/02/12 00:03:11 Am I right in thinking that if this path has been
asanka 2016/02/12 05:04:26 I moved the download_file_ handling to one place,
1493 }
1494 break;
1495
1496 case INITIAL_INTERNAL:
1497 case MAX_DOWNLOAD_INTERNAL_STATE:
1498 NOTREACHED();
1499 return;
1500 }
1446 1501
1447 last_reason_ = reason; 1502 last_reason_ = reason;
1448 1503 if (download_file_) {
1449 ResumeMode resume_mode = GetResumeMode(); 1504 ResumeMode resume_mode = GetResumeMode();
1450 1505 ReleaseDownloadFile(resume_mode != RESUME_MODE_IMMEDIATE_CONTINUE &&
1451 if (state_ == IN_PROGRESS_INTERNAL) { 1506 resume_mode != RESUME_MODE_USER_CONTINUE);
1452 // Cancel (delete file) if:
1453 // 1) we're going to restart.
1454 // 2) Resumption isn't possible (download was cancelled or blocked due to
1455 // security restrictions).
1456 // 3) Resumption isn't enabled.
1457 // No point in leaving data around we aren't going to use.
1458 ReleaseDownloadFile(resume_mode == RESUME_MODE_IMMEDIATE_RESTART ||
1459 resume_mode == RESUME_MODE_USER_RESTART ||
1460 resume_mode == RESUME_MODE_INVALID ||
1461 !IsDownloadResumptionEnabled());
1462
1463 // Cancel the originating URL request.
1464 request_handle_->CancelRequest();
1465 } else {
1466 DCHECK(!download_file_.get());
1467 } 1507 }
1468 1508
1469 // Reset all data saved, as even if we did save all the data we're going 1509 // Reset all data saved, as even if we did save all the data we're going to go
1470 // to go through another round of downloading when we resume. 1510 // through another round of downloading when we resume. There's a potential
1471 // There's a potential problem here in the abstract, as if we did download 1511 // problem here in the abstract, as if we did download all the data and then
1472 // all the data and then run into a continuable error, on resumption we 1512 // run into a continuable error, on resumption we won't download any more
1473 // won't download any more data. However, a) there are currently no 1513 // data. However, a) there are currently no continuable errors that can occur
1474 // continuable errors that can occur after we download all the data, and 1514 // after we download all the data, and b) if there were, that would probably
1475 // b) if there were, that would probably simply result in a null range 1515 // simply result in a null range request, which would generate a
1476 // request, which would generate a DestinationCompleted() notification 1516 // DestinationCompleted() notification from the DownloadFile, which would
1477 // from the DownloadFile, which would behave properly with setting 1517 // behave properly with setting all_data_saved_ to false here.
1478 // all_data_saved_ to false here.
1479 all_data_saved_ = false; 1518 all_data_saved_ = false;
1480 1519
1481 TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS); 1520 if (request_handle_)
1482 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); 1521 request_handle_->CancelRequest();
1483 if (!GetWebContents())
1484 RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
1485 1522
1486 AutoResumeIfValid(); 1523 if (reason == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED ||
1524 reason == DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN) {
1525 if (IsDangerous()) {
1526 RecordDangerousDownloadDiscard(
1527 reason == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
1528 ? DOWNLOAD_DISCARD_DUE_TO_USER_ACTION
1529 : DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN,
1530 GetDangerType(), GetTargetFilePath());
1531 }
1532
1533 RecordDownloadCount(CANCELLED_COUNT);
1534 TransitionTo(CANCELLED_INTERNAL, DONT_UPDATE_OBSERVERS);
1535 } else {
1536 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
1537 if (!GetWebContents())
1538 RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
1539 TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS);
1540 AutoResumeIfValid();
1541 }
1542
1487 UpdateObservers(); 1543 UpdateObservers();
1488 } 1544 }
1489 1545
1490 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) { 1546 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) {
1491 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1547 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1548 DVLOG(20) << __FUNCTION__ << "() destroy_file:" << destroy_file;
1492 1549
1493 if (destroy_file) { 1550 if (destroy_file) {
1494 BrowserThread::PostTask( 1551 BrowserThread::PostTask(
1495 BrowserThread::FILE, FROM_HERE, 1552 BrowserThread::FILE, FROM_HERE,
1496 // Will be deleted at end of task execution. 1553 // Will be deleted at end of task execution.
1497 base::Bind(&DownloadFileCancel, base::Passed(&download_file_))); 1554 base::Bind(&DownloadFileCancel, base::Passed(&download_file_)));
1498 // Avoid attempting to reuse the intermediate file by clearing out 1555 // Avoid attempting to reuse the intermediate file by clearing out
1499 // current_path_. 1556 // current_path_.
1500 current_path_.clear(); 1557 current_path_.clear();
1501 } else { 1558 } else {
1502 BrowserThread::PostTask( 1559 BrowserThread::PostTask(
1503 BrowserThread::FILE, 1560 BrowserThread::FILE,
1504 FROM_HERE, 1561 FROM_HERE,
1505 base::Bind(base::IgnoreResult(&DownloadFileDetach), 1562 base::Bind(base::IgnoreResult(&DownloadFileDetach),
1506 // Will be deleted at end of task execution. 1563 // Will be deleted at end of task execution.
1507 base::Passed(&download_file_))); 1564 base::Passed(&download_file_)));
1508 } 1565 }
1509 // Don't accept any more messages from the DownloadFile, and null 1566 // Don't accept any more messages from the DownloadFile, and null
1510 // out any previous "all data received". This also breaks links to 1567 // out any previous "all data received". This also breaks links to
1511 // other entities we've given out weak pointers to. 1568 // other entities we've given out weak pointers to.
1512 weak_ptr_factory_.InvalidateWeakPtrs(); 1569 weak_ptr_factory_.InvalidateWeakPtrs();
1513 } 1570 }
1514 1571
1515 bool DownloadItemImpl::IsDownloadReadyForCompletion( 1572 bool DownloadItemImpl::IsDownloadReadyForCompletion(
1516 const base::Closure& state_change_notification) { 1573 const base::Closure& state_change_notification) {
1574 // If the download hasn't progressed to the IN_PROGRESS state, then it's not
1575 // ready for completion.
1576 if (state_ != IN_PROGRESS_INTERNAL)
1577 return false;
1578
1517 // If we don't have all the data, the download is not ready for 1579 // If we don't have all the data, the download is not ready for
1518 // completion. 1580 // completion.
1519 if (!AllDataSaved()) 1581 if (!AllDataSaved())
1520 return false; 1582 return false;
1521 1583
1522 // If the download is dangerous, but not yet validated, it's not ready for 1584 // If the download is dangerous, but not yet validated, it's not ready for
1523 // completion. 1585 // completion.
1524 if (IsDangerous()) 1586 if (IsDangerous())
1525 return false; 1587 return false;
1526 1588
1527 // If the download isn't active (e.g. has been cancelled) it's not 1589 // Invariants for the IN_PROGRESS state. DCHECKs here verify that the
1528 // ready for completion. 1590 // invariants are still true.
1529 if (state_ != IN_PROGRESS_INTERNAL) 1591 DCHECK(!target_path_.empty());
1530 return false; 1592 DCHECK(!current_path_.empty());
1531 1593 DCHECK(target_path_.DirName() == current_path_.DirName());
1532 // If the target filename hasn't been determined, then it's not ready for
1533 // completion. This is checked in ReadyForDownloadCompletionDone().
1534 if (GetTargetFilePath().empty())
1535 return false;
1536
1537 // This is checked in NeedsRename(). Without this conditional,
1538 // browser_tests:DownloadTest.DownloadMimeType fails the DCHECK.
1539 if (target_path_.DirName() != current_path_.DirName())
1540 return false;
1541 1594
1542 // Give the delegate a chance to hold up a stop sign. It'll call 1595 // Give the delegate a chance to hold up a stop sign. It'll call
1543 // use back through the passed callback if it does and that state changes. 1596 // use back through the passed callback if it does and that state changes.
1544 if (!delegate_->ShouldCompleteDownload(this, state_change_notification)) 1597 if (!delegate_->ShouldCompleteDownload(this, state_change_notification))
1545 return false; 1598 return false;
1546 1599
1547 return true; 1600 return true;
1548 } 1601 }
1549 1602
1550 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state, 1603 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
Randy Smith (Not in Mondays) 2016/02/12 00:03:10 Nice invariant checking.
asanka 2016/02/12 05:04:26 Thanks!
1551 ShouldUpdateObservers notify_action) { 1604 ShouldUpdateObservers notify_action) {
1552 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1605 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1553 1606
1554 if (state_ == new_state) 1607 if (state_ == new_state)
1555 return; 1608 return;
1556 1609
1557 DownloadInternalState old_state = state_; 1610 DownloadInternalState old_state = state_;
1558 state_ = new_state; 1611 state_ = new_state;
1559 1612
1613 DCHECK(is_save_package_download_
1614 ? IsValidSavePackageStateTransition(old_state, new_state)
1615 : IsValidStateTransition(old_state, new_state))
1616 << "Invalid state transition from:" << DebugDownloadStateString(old_state)
1617 << " to:" << DebugDownloadStateString(new_state);
1618
1560 switch (state_) { 1619 switch (state_) {
1620 case INITIAL_INTERNAL:
1621 NOTREACHED();
1622 break;
1623
1624 case TARGET_PENDING_INTERNAL:
1625 case TARGET_RESOLVED_INTERNAL:
1626 break;
1627
1628 case IN_PROGRESS_INTERNAL:
1629 DCHECK(!current_path_.empty()) << "Current output path must be known.";
1630 DCHECK(!target_path_.empty()) << "Target path must be known.";
1631 DCHECK(current_path_.DirName() == target_path_.DirName())
1632 << "Current output directory must match target directory.";
1633 DCHECK(download_file_) << "Output file must be owned by download item.";
1634 DCHECK(request_handle_) << "Download source must be active.";
1635 DCHECK(!is_paused_) << "At the time a download enters IN_PROGRESS state, "
1636 "it must not be paused.";
1637 break;
1638
1561 case COMPLETING_INTERNAL: 1639 case COMPLETING_INTERNAL:
1640 DCHECK(all_data_saved_) << "All data must be saved prior to completion.";
1641 DCHECK(!download_file_)
1642 << "Download file must be released prior to completion.";
1643 DCHECK(!target_path_.empty()) << "Target path must be known.";
1644 DCHECK(current_path_ == target_path_)
1645 << "Current output path must match target path.";
1646
1562 bound_net_log_.AddEvent( 1647 bound_net_log_.AddEvent(
1563 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING, 1648 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING,
1564 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_)); 1649 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_));
1565 break; 1650 break;
1651
1566 case COMPLETE_INTERNAL: 1652 case COMPLETE_INTERNAL:
1567 bound_net_log_.AddEvent( 1653 bound_net_log_.AddEvent(
1568 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED, 1654 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED,
1569 base::Bind(&ItemFinishedNetLogCallback, auto_opened_)); 1655 base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
1570 break; 1656 break;
1657
1571 case INTERRUPTED_INTERNAL: 1658 case INTERRUPTED_INTERNAL:
1572 bound_net_log_.AddEvent( 1659 bound_net_log_.AddEvent(
1573 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED, 1660 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED,
1574 base::Bind(&ItemInterruptedNetLogCallback, last_reason_, 1661 base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
1575 received_bytes_, &hash_state_)); 1662 received_bytes_, &hash_state_));
1576 break; 1663 break;
1577 case IN_PROGRESS_INTERNAL: 1664
1578 if (old_state == INTERRUPTED_INTERNAL) { 1665 case RESUMING_INTERNAL:
1579 bound_net_log_.AddEvent( 1666 bound_net_log_.AddEvent(
1580 net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED, 1667 net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
1581 base::Bind(&ItemResumingNetLogCallback, 1668 base::Bind(&ItemResumingNetLogCallback, false, last_reason_,
1582 false, last_reason_, received_bytes_, &hash_state_)); 1669 received_bytes_, &hash_state_));
1583 }
1584 break; 1670 break;
1671
1585 case CANCELLED_INTERNAL: 1672 case CANCELLED_INTERNAL:
1586 bound_net_log_.AddEvent( 1673 bound_net_log_.AddEvent(
1587 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED, 1674 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
1588 base::Bind(&ItemCanceledNetLogCallback, received_bytes_, 1675 base::Bind(&ItemCanceledNetLogCallback, received_bytes_,
1589 &hash_state_)); 1676 &hash_state_));
1590 break; 1677 break;
1591 default: 1678
1679 case MAX_DOWNLOAD_INTERNAL_STATE:
1680 NOTREACHED();
1592 break; 1681 break;
1593 } 1682 }
1594 1683
1595 DVLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true) 1684 DVLOG(20) << " " << __FUNCTION__ << "()"
1596 << " " << InternalToExternalState(old_state) 1685 << " from:" << DebugDownloadStateString(old_state)
1597 << " " << InternalToExternalState(state_); 1686 << " to:" << DebugDownloadStateString(state_)
1598 1687 << " this = " << DebugString(true);
1599 bool is_done = (state_ != IN_PROGRESS_INTERNAL && 1688 bool is_done =
Randy Smith (Not in Mondays) 2016/02/12 00:03:11 nit, suggestion: I'm feeling tempted to suggest in
asanka 2016/02/12 05:04:26 Done.
1600 state_ != COMPLETING_INTERNAL); 1689 (state_ != TARGET_PENDING_INTERNAL &&
1601 bool was_done = (old_state != IN_PROGRESS_INTERNAL && 1690 state_ != TARGET_RESOLVED_INTERNAL && state_ != IN_PROGRESS_INTERNAL &&
1602 old_state != COMPLETING_INTERNAL); 1691 state_ != COMPLETING_INTERNAL);
1692 bool was_done =
1693 (old_state != TARGET_PENDING_INTERNAL &&
1694 old_state != TARGET_RESOLVED_INTERNAL &&
1695 old_state != IN_PROGRESS_INTERNAL && old_state != COMPLETING_INTERNAL);
1603 // Termination 1696 // Termination
1604 if (is_done && !was_done) 1697 if (is_done && !was_done)
1605 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE); 1698 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
1606 1699
1607 // Resumption 1700 // Resumption
1608 if (was_done && !is_done) { 1701 if (was_done && !is_done) {
1609 std::string file_name(target_path_.BaseName().AsUTF8Unsafe()); 1702 std::string file_name(target_path_.BaseName().AsUTF8Unsafe());
1610 bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, 1703 bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE,
1611 base::Bind(&ItemActivatedNetLogCallback, 1704 base::Bind(&ItemActivatedNetLogCallback,
1612 this, SRC_ACTIVE_DOWNLOAD, 1705 this, SRC_ACTIVE_DOWNLOAD,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1697 1790
1698 download_params->set_file_path(GetFullPath()); 1791 download_params->set_file_path(GetFullPath());
1699 download_params->set_offset(GetReceivedBytes()); 1792 download_params->set_offset(GetReceivedBytes());
1700 download_params->set_hash_state(GetHashState()); 1793 download_params->set_hash_state(GetHashState());
1701 download_params->set_last_modified(GetLastModifiedTime()); 1794 download_params->set_last_modified(GetLastModifiedTime());
1702 download_params->set_etag(GetETag()); 1795 download_params->set_etag(GetETag());
1703 download_params->set_callback( 1796 download_params->set_callback(
1704 base::Bind(&DownloadItemImpl::OnResumeRequestStarted, 1797 base::Bind(&DownloadItemImpl::OnResumeRequestStarted,
1705 weak_ptr_factory_.GetWeakPtr())); 1798 weak_ptr_factory_.GetWeakPtr()));
1706 1799
1800 TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS);
1707 delegate_->ResumeInterruptedDownload(std::move(download_params), GetId()); 1801 delegate_->ResumeInterruptedDownload(std::move(download_params), GetId());
1708 // Just in case we were interrupted while paused. 1802 // Just in case we were interrupted while paused.
1709 is_paused_ = false; 1803 is_paused_ = false;
1710
1711 TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS);
1712 } 1804 }
1713 1805
1714 // static 1806 // static
1715 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( 1807 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
1716 DownloadInternalState internal_state) { 1808 DownloadInternalState internal_state) {
1717 switch (internal_state) { 1809 switch (internal_state) {
1810 case INITIAL_INTERNAL:
1811 case TARGET_PENDING_INTERNAL:
1812 case TARGET_RESOLVED_INTERNAL:
1813 // TODO(asanka): Introduce an externally visible state to distinguish
1814 // between the above states and IN_PROGRESS_INTERNAL. The latter (the
1815 // state where the download is active and has a known target) is the state
1816 // that most external users are interested in.
1718 case IN_PROGRESS_INTERNAL: 1817 case IN_PROGRESS_INTERNAL:
1719 return IN_PROGRESS; 1818 return IN_PROGRESS;
1720 case COMPLETING_INTERNAL: 1819 case COMPLETING_INTERNAL:
1721 return IN_PROGRESS; 1820 return IN_PROGRESS;
1722 case COMPLETE_INTERNAL: 1821 case COMPLETE_INTERNAL:
1723 return COMPLETE; 1822 return COMPLETE;
1724 case CANCELLED_INTERNAL: 1823 case CANCELLED_INTERNAL:
1725 return CANCELLED; 1824 return CANCELLED;
1726 case INTERRUPTED_INTERNAL: 1825 case INTERRUPTED_INTERNAL:
1727 return INTERRUPTED; 1826 return INTERRUPTED;
(...skipping 18 matching lines...) Expand all
1746 case CANCELLED: 1845 case CANCELLED:
1747 return CANCELLED_INTERNAL; 1846 return CANCELLED_INTERNAL;
1748 case INTERRUPTED: 1847 case INTERRUPTED:
1749 return INTERRUPTED_INTERNAL; 1848 return INTERRUPTED_INTERNAL;
1750 default: 1849 default:
1751 NOTREACHED(); 1850 NOTREACHED();
1752 } 1851 }
1753 return MAX_DOWNLOAD_INTERNAL_STATE; 1852 return MAX_DOWNLOAD_INTERNAL_STATE;
1754 } 1853 }
1755 1854
1855 #if DCHECK_IS_ON()
Randy Smith (Not in Mondays) 2016/02/12 00:03:11 nit, suggestion: I wince a bit at declaration a ro
asanka 2016/02/12 05:04:26 Opted to put the #if in the .h file.
asanka 2016/02/12 15:53:36 Well, that didn't. Apparently the symbol still nee
1856 // static
1857 bool DownloadItemImpl::IsValidSavePackageStateTransition(
1858 DownloadInternalState from,
1859 DownloadInternalState to) {
1860 switch (from) {
1861 case INITIAL_INTERNAL:
1862 case TARGET_PENDING_INTERNAL:
1863 case TARGET_RESOLVED_INTERNAL:
1864 case COMPLETING_INTERNAL:
1865 case COMPLETE_INTERNAL:
1866 case INTERRUPTED_INTERNAL:
1867 case RESUMING_INTERNAL:
1868 case CANCELLED_INTERNAL:
1869 return false;
1870
1871 case IN_PROGRESS_INTERNAL:
1872 return to == CANCELLED_INTERNAL || COMPLETE_INTERNAL;
Randy Smith (Not in Mondays) 2016/02/12 00:03:10 I think you were typing a little too fast here :-}
asanka 2016/02/12 05:04:26 Hehe :) Done.
1873
1874 case MAX_DOWNLOAD_INTERNAL_STATE:
1875 NOTREACHED();
1876 }
1877 return false;
1878 }
1879
1880 // static
1881 bool DownloadItemImpl::IsValidStateTransition(DownloadInternalState from,
1882 DownloadInternalState to) {
1883 switch (from) {
1884 case INITIAL_INTERNAL:
1885 return to == TARGET_PENDING_INTERNAL || to == INTERRUPTED_INTERNAL;
1886
1887 case TARGET_PENDING_INTERNAL:
1888 return to == TARGET_RESOLVED_INTERNAL || to == CANCELLED_INTERNAL;
1889
1890 case TARGET_RESOLVED_INTERNAL:
1891 return to == IN_PROGRESS_INTERNAL || to == INTERRUPTED_INTERNAL ||
1892 to == CANCELLED_INTERNAL;
1893
1894 case IN_PROGRESS_INTERNAL:
1895 return to == COMPLETING_INTERNAL || to == CANCELLED_INTERNAL ||
1896 to == INTERRUPTED_INTERNAL;
1897
1898 case COMPLETING_INTERNAL:
1899 return to == COMPLETE_INTERNAL;
1900
1901 case COMPLETE_INTERNAL:
1902 return false;
1903
1904 case INTERRUPTED_INTERNAL:
1905 return to == RESUMING_INTERNAL || to == CANCELLED_INTERNAL;
1906
1907 case RESUMING_INTERNAL:
1908 return to == TARGET_PENDING_INTERNAL || to == CANCELLED_INTERNAL;
1909
1910 case CANCELLED_INTERNAL:
1911 return false;
1912
1913 case MAX_DOWNLOAD_INTERNAL_STATE:
1914 NOTREACHED();
1915 }
1916 return false;
1917 }
1918 #endif // DCHECK_IS_ON()
1919
1756 const char* DownloadItemImpl::DebugDownloadStateString( 1920 const char* DownloadItemImpl::DebugDownloadStateString(
1757 DownloadInternalState state) { 1921 DownloadInternalState state) {
1758 switch (state) { 1922 switch (state) {
1923 case INITIAL_INTERNAL:
1924 return "INITIAL";
1925 case TARGET_PENDING_INTERNAL:
1926 return "TARGET_PENDING";
1927 case TARGET_RESOLVED_INTERNAL:
1928 return "TARGET_RESOLVED";
1759 case IN_PROGRESS_INTERNAL: 1929 case IN_PROGRESS_INTERNAL:
1760 return "IN_PROGRESS"; 1930 return "IN_PROGRESS";
1761 case COMPLETING_INTERNAL: 1931 case COMPLETING_INTERNAL:
1762 return "COMPLETING"; 1932 return "COMPLETING";
1763 case COMPLETE_INTERNAL: 1933 case COMPLETE_INTERNAL:
1764 return "COMPLETE"; 1934 return "COMPLETE";
1765 case CANCELLED_INTERNAL: 1935 case CANCELLED_INTERNAL:
1766 return "CANCELLED"; 1936 return "CANCELLED";
1767 case INTERRUPTED_INTERNAL: 1937 case INTERRUPTED_INTERNAL:
1768 return "INTERRUPTED"; 1938 return "INTERRUPTED";
(...skipping 17 matching lines...) Expand all
1786 case RESUME_MODE_USER_CONTINUE: 1956 case RESUME_MODE_USER_CONTINUE:
1787 return "USER_CONTINUE"; 1957 return "USER_CONTINUE";
1788 case RESUME_MODE_USER_RESTART: 1958 case RESUME_MODE_USER_RESTART:
1789 return "USER_RESTART"; 1959 return "USER_RESTART";
1790 } 1960 }
1791 NOTREACHED() << "Unknown resume mode " << mode; 1961 NOTREACHED() << "Unknown resume mode " << mode;
1792 return "unknown"; 1962 return "unknown";
1793 } 1963 }
1794 1964
1795 } // namespace content 1965 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698