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

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: Address comments and fix DownloadsExtensionTest 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 IN_PROGRESS_INTERNAL:
365 request_handle_->PauseRequest();
366 is_paused_ = true;
367 UpdateObservers();
368 return;
369
370 case MAX_DOWNLOAD_INTERNAL_STATE:
371 case TARGET_RESOLVED_INTERNAL:
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 DCHECK(!is_paused_);
387 return;
388
389 case TARGET_PENDING_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:
404 case TARGET_RESOLVED_INTERNAL:
379 NOTREACHED(); 405 NOTREACHED();
380 } 406 }
381 } 407 }
382 408
383 void DownloadItemImpl::Cancel(bool user_cancel) { 409 void DownloadItemImpl::Cancel(bool user_cancel) {
384 DCHECK_CURRENTLY_ON(BrowserThread::UI); 410 DCHECK_CURRENTLY_ON(BrowserThread::UI);
385
386 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); 411 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
387 if (state_ != IN_PROGRESS_INTERNAL && 412 Interrupt(user_cancel ? DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
388 state_ != INTERRUPTED_INTERNAL && 413 : 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_)
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 } 414 }
432 415
433 void DownloadItemImpl::Remove() { 416 void DownloadItemImpl::Remove() {
434 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); 417 DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
435 DCHECK_CURRENTLY_ON(BrowserThread::UI); 418 DCHECK_CURRENTLY_ON(BrowserThread::UI);
436 419
437 delegate_->AssertStateConsistent(this); 420 delegate_->AssertStateConsistent(this);
438 Cancel(true); 421 Interrupt(DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
439 delegate_->AssertStateConsistent(this); 422 delegate_->AssertStateConsistent(this);
440 423
441 NotifyRemoved(); 424 NotifyRemoved();
442 delegate_->DownloadRemoved(this); 425 delegate_->DownloadRemoved(this);
443 // We have now been deleted. 426 // We have now been deleted.
444 } 427 }
445 428
446 void DownloadItemImpl::OpenDownload() { 429 void DownloadItemImpl::OpenDownload() {
447 DCHECK_CURRENTLY_ON(BrowserThread::UI); 430 DCHECK_CURRENTLY_ON(BrowserThread::UI);
448 431
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 471
489 bool DownloadItemImpl::IsPaused() const { 472 bool DownloadItemImpl::IsPaused() const {
490 return is_paused_; 473 return is_paused_;
491 } 474 }
492 475
493 bool DownloadItemImpl::IsTemporary() const { 476 bool DownloadItemImpl::IsTemporary() const {
494 return is_temporary_; 477 return is_temporary_;
495 } 478 }
496 479
497 bool DownloadItemImpl::CanResume() const { 480 bool DownloadItemImpl::CanResume() const {
498 if ((GetState() == IN_PROGRESS) && IsPaused()) 481 DCHECK_CURRENTLY_ON(BrowserThread::UI);
499 return true; 482 switch (state_) {
483 case INITIAL_INTERNAL:
484 case COMPLETING_INTERNAL:
485 case COMPLETE_INTERNAL:
486 case CANCELLED_INTERNAL:
487 case RESUMING_INTERNAL:
488 return false;
500 489
501 if (state_ != INTERRUPTED_INTERNAL) 490 case TARGET_PENDING_INTERNAL:
502 return false; 491 case TARGET_RESOLVED_INTERNAL:
492 case IN_PROGRESS_INTERNAL:
493 return is_paused_;
503 494
504 // We currently only support HTTP(S) requests for download resumption. 495 case INTERRUPTED_INTERNAL: {
505 if (!GetURL().SchemeIsHTTPOrHTTPS()) 496 ResumeMode resume_mode = GetResumeMode();
506 return false; 497 // Only allow Resume() calls if the resumption mode requires a user
498 // action.
499 return IsDownloadResumptionEnabled() &&
500 (resume_mode == RESUME_MODE_USER_RESTART ||
501 resume_mode == RESUME_MODE_USER_CONTINUE);
502 }
507 503
508 ResumeMode resume_mode = GetResumeMode(); 504 case MAX_DOWNLOAD_INTERNAL_STATE:
509 return IsDownloadResumptionEnabled() && 505 NOTREACHED();
510 (resume_mode == RESUME_MODE_USER_RESTART || 506 }
511 resume_mode == RESUME_MODE_USER_CONTINUE); 507 return false;
512 } 508 }
513 509
514 bool DownloadItemImpl::IsDone() const { 510 bool DownloadItemImpl::IsDone() const {
515 switch (state_) { 511 switch (state_) {
512 case INITIAL_INTERNAL:
513 case COMPLETING_INTERNAL:
514 case RESUMING_INTERNAL:
515 case TARGET_PENDING_INTERNAL:
516 case TARGET_RESOLVED_INTERNAL:
516 case IN_PROGRESS_INTERNAL: 517 case IN_PROGRESS_INTERNAL:
517 case COMPLETING_INTERNAL:
518 return false; 518 return false;
519 519
520 case COMPLETE_INTERNAL: 520 case COMPLETE_INTERNAL:
521 case CANCELLED_INTERNAL: 521 case CANCELLED_INTERNAL:
522 return true; 522 return true;
523 523
524 case INTERRUPTED_INTERNAL: 524 case INTERRUPTED_INTERNAL:
525 return !CanResume(); 525 return !CanResume();
526 526
527 case RESUMING_INTERNAL:
528 return false;
529
530 case MAX_DOWNLOAD_INTERNAL_STATE: 527 case MAX_DOWNLOAD_INTERNAL_STATE:
531 break; 528 NOTREACHED();
532 } 529 }
533 NOTREACHED(); 530 return false;
534 return true;
535 } 531 }
536 532
537 const GURL& DownloadItemImpl::GetURL() const { 533 const GURL& DownloadItemImpl::GetURL() const {
538 return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.back(); 534 return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.back();
539 } 535 }
540 536
541 const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const { 537 const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const {
542 return url_chain_; 538 return url_chain_;
543 } 539 }
544 540
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 // Currently such items have null request_handle_s, where other items 759 // Currently such items have null request_handle_s, where other items
764 // (regular and SavePackage downloads) have actual objects off the pointer. 760 // (regular and SavePackage downloads) have actual objects off the pointer.
765 if (request_handle_) 761 if (request_handle_)
766 return request_handle_->GetWebContents(); 762 return request_handle_->GetWebContents();
767 return NULL; 763 return NULL;
768 } 764 }
769 765
770 void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type) { 766 void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type) {
771 DCHECK_CURRENTLY_ON(BrowserThread::UI); 767 DCHECK_CURRENTLY_ON(BrowserThread::UI);
772 DCHECK(AllDataSaved()); 768 DCHECK(AllDataSaved());
769
770 // Danger type is only allowed to be set on an active download after all data
771 // has been saved. This excludes all other states. In particular,
772 // OnContentCheckCompleted() isn't allowed on an INTERRUPTED download since
773 // such an interruption would need to happen between OnAllDataSaved() and
774 // OnContentCheckCompleted() during which no disk or network activity
775 // should've taken place.
776 DCHECK_EQ(state_, IN_PROGRESS_INTERNAL);
773 DVLOG(20) << __FUNCTION__ << " danger_type=" << danger_type 777 DVLOG(20) << __FUNCTION__ << " danger_type=" << danger_type
774 << " download=" << DebugString(true); 778 << " download=" << DebugString(true);
775 SetDangerType(danger_type); 779 SetDangerType(danger_type);
776 UpdateObservers(); 780 UpdateObservers();
777 } 781 }
778 782
779 void DownloadItemImpl::SetOpenWhenComplete(bool open) { 783 void DownloadItemImpl::SetOpenWhenComplete(bool open) {
780 open_when_complete_ = open; 784 open_when_complete_ = open;
781 } 785 }
782 786
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
847 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); 851 description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
848 } 852 }
849 853
850 description += " }"; 854 description += " }";
851 855
852 return description; 856 return description;
853 } 857 }
854 858
855 DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const { 859 DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
856 DCHECK_CURRENTLY_ON(BrowserThread::UI); 860 DCHECK_CURRENTLY_ON(BrowserThread::UI);
861
862 if (!IsDownloadResumptionEnabled())
863 return RESUME_MODE_INVALID;
864
865 // Only support resumption for HTTP(S).
866 if (!GetURL().SchemeIsHTTPOrHTTPS())
867 return RESUME_MODE_INVALID;
868
857 // We can't continue without a handle on the intermediate file. 869 // 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 870 // We also can't continue if we don't have some verifier to make sure
859 // we're getting the same file. 871 // we're getting the same file.
860 const bool force_restart = 872 const bool force_restart =
861 (current_path_.empty() || (etag_.empty() && last_modified_time_.empty())); 873 (current_path_.empty() || (etag_.empty() && last_modified_time_.empty()));
862 874
863 // We won't auto-restart if we've used up our attempts or the 875 // We won't auto-restart if we've used up our attempts or the
864 // download has been paused by user action. 876 // download has been paused by user action.
865 const bool force_user = 877 const bool force_user =
866 (auto_resume_count_ >= kMaxAutoResumeAttempts || is_paused_); 878 (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 { 999 const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
988 return bound_net_log_; 1000 return bound_net_log_;
989 } 1001 }
990 1002
991 void DownloadItemImpl::SetTotalBytes(int64_t total_bytes) { 1003 void DownloadItemImpl::SetTotalBytes(int64_t total_bytes) {
992 total_bytes_ = total_bytes; 1004 total_bytes_ = total_bytes;
993 } 1005 }
994 1006
995 void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) { 1007 void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
996 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1008 DCHECK_CURRENTLY_ON(BrowserThread::UI);
997
998 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
999 DCHECK(!all_data_saved_); 1009 DCHECK(!all_data_saved_);
1000 all_data_saved_ = true; 1010 all_data_saved_ = true;
1001 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); 1011 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
1002 1012
1003 // Store final hash and null out intermediate serialized hash state. 1013 // Store final hash and null out intermediate serialized hash state.
1004 hash_ = final_hash; 1014 hash_ = final_hash;
1005 hash_state_ = ""; 1015 hash_state_ = "";
1006 1016
1007 UpdateObservers(); 1017 UpdateObservers();
1008 } 1018 }
1009 1019
1010 void DownloadItemImpl::MarkAsComplete() { 1020 void DownloadItemImpl::MarkAsComplete() {
1011 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1021 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1012 1022
1013 DCHECK(all_data_saved_); 1023 DCHECK(all_data_saved_);
1014 end_time_ = base::Time::Now(); 1024 end_time_ = base::Time::Now();
1015 TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS); 1025 TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS);
1016 } 1026 }
1017 1027
1018 void DownloadItemImpl::DestinationUpdate(int64_t bytes_so_far, 1028 void DownloadItemImpl::DestinationUpdate(int64_t bytes_so_far,
1019 int64_t bytes_per_sec, 1029 int64_t bytes_per_sec,
1020 const std::string& hash_state) { 1030 const std::string& hash_state) {
1021 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1031 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1032 // If the download is in any other state we don't expect any
1033 // DownloadDestinationObserver callbacks. An interruption or a cancellation
1034 // results in a call to ReleaseDownloadFile which invalidates the weak
1035 // reference held by the DownloadFile and hence cuts off any pending
1036 // callbacks.
1037 DCHECK(state_ == TARGET_PENDING_INTERNAL || state_ == IN_PROGRESS_INTERNAL);
1022 DVLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far 1038 DVLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far
1023 << " per_sec=" << bytes_per_sec << " download=" 1039 << " per_sec=" << bytes_per_sec
1024 << DebugString(true); 1040 << " download=" << DebugString(true);
1025 1041
1026 if (GetState() != IN_PROGRESS) {
1027 // Ignore if we're no longer in-progress. This can happen if we race a
1028 // Cancel on the UI thread with an update on the FILE thread.
1029 //
1030 // TODO(rdsmith): Arguably we should let this go through, as this means
1031 // the download really did get further than we know before it was
1032 // cancelled. But the gain isn't very large, and the code is more
1033 // fragile if it has to support in progress updates in a non-in-progress
1034 // state. This issue should be readdressed when we revamp performance
1035 // reporting.
1036 return;
1037 }
1038 bytes_per_sec_ = bytes_per_sec; 1042 bytes_per_sec_ = bytes_per_sec;
1039 hash_state_ = hash_state; 1043 hash_state_ = hash_state;
1040 received_bytes_ = bytes_so_far; 1044 received_bytes_ = bytes_so_far;
1041 1045
1042 // If we've received more data than we were expecting (bad server info?), 1046 // If we've received more data than we were expecting (bad server info?),
1043 // revert to 'unknown size mode'. 1047 // revert to 'unknown size mode'.
1044 if (received_bytes_ > total_bytes_) 1048 if (received_bytes_ > total_bytes_)
1045 total_bytes_ = 0; 1049 total_bytes_ = 0;
1046 1050
1047 if (bound_net_log_.IsCapturing()) { 1051 if (bound_net_log_.IsCapturing()) {
1048 bound_net_log_.AddEvent( 1052 bound_net_log_.AddEvent(
1049 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED, 1053 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
1050 net::NetLog::Int64Callback("bytes_so_far", received_bytes_)); 1054 net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
1051 } 1055 }
1052 1056
1053 UpdateObservers(); 1057 UpdateObservers();
1054 } 1058 }
1055 1059
1056 void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) { 1060 void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) {
1061 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1062 // If the download is in any other state we don't expect any
1063 // DownloadDestinationObserver callbacks. An interruption or a cancellation
1064 // results in a call to ReleaseDownloadFile which invalidates the weak
1065 // reference held by the DownloadFile and hence cuts off any pending
1066 // callbacks.
1067 DCHECK(state_ == TARGET_PENDING_INTERNAL || state_ == IN_PROGRESS_INTERNAL);
1068 DVLOG(20) << __FUNCTION__
1069 << "() reason:" << DownloadInterruptReasonToString(reason);
1070
1057 // Postpone recognition of this error until after file name determination 1071 // Postpone recognition of this error until after file name determination
1058 // has completed and the intermediate file has been renamed to simplify 1072 // has completed and the intermediate file has been renamed to simplify
1059 // resumption conditions. 1073 // resumption conditions.
1060 if (current_path_.empty() || target_path_.empty()) 1074 if (state_ != IN_PROGRESS_INTERNAL)
1061 destination_error_ = reason; 1075 destination_error_ = reason;
1062 else 1076 else
1063 Interrupt(reason); 1077 Interrupt(reason);
1064 } 1078 }
1065 1079
1066 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) { 1080 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
1081 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1082 // If the download is in any other state we don't expect any
1083 // DownloadDestinationObserver callbacks. An interruption or a cancellation
1084 // results in a call to ReleaseDownloadFile which invalidates the weak
1085 // reference held by the DownloadFile and hence cuts off any pending
1086 // callbacks.
1087 DCHECK(state_ == TARGET_PENDING_INTERNAL || state_ == IN_PROGRESS_INTERNAL);
1067 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); 1088 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
1068 if (GetState() != IN_PROGRESS) 1089
1069 return;
1070 OnAllDataSaved(final_hash); 1090 OnAllDataSaved(final_hash);
1071 MaybeCompleteDownload(); 1091 MaybeCompleteDownload();
1072 } 1092 }
1073 1093
1074 // **** Download progression cascade 1094 // **** Download progression cascade
1075 1095
1076 void DownloadItemImpl::Init(bool active, 1096 void DownloadItemImpl::Init(bool active,
1077 DownloadType download_type) { 1097 DownloadType download_type) {
1078 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1098 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1079 1099
(...skipping 29 matching lines...) Expand all
1109 } 1129 }
1110 1130
1111 // We're starting the download. 1131 // We're starting the download.
1112 void DownloadItemImpl::Start( 1132 void DownloadItemImpl::Start(
1113 scoped_ptr<DownloadFile> file, 1133 scoped_ptr<DownloadFile> file,
1114 scoped_ptr<DownloadRequestHandleInterface> req_handle) { 1134 scoped_ptr<DownloadRequestHandleInterface> req_handle) {
1115 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1135 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1116 DCHECK(!download_file_.get()); 1136 DCHECK(!download_file_.get());
1117 DCHECK(file.get()); 1137 DCHECK(file.get());
1118 DCHECK(req_handle.get()); 1138 DCHECK(req_handle.get());
1139 DVLOG(20) << __FUNCTION__ << "() this=" << DebugString(true);
1119 1140
1120 download_file_ = std::move(file); 1141 download_file_ = std::move(file);
1121 request_handle_ = std::move(req_handle); 1142 request_handle_ = std::move(req_handle);
1122 1143
1123 if (GetState() == CANCELLED) { 1144 if (state_ == CANCELLED_INTERNAL) {
1124 // The download was in the process of resuming when it was cancelled. Don't 1145 // The download was in the process of resuming when it was cancelled. Don't
1125 // proceed. 1146 // proceed.
1126 ReleaseDownloadFile(true); 1147 ReleaseDownloadFile(true);
1127 request_handle_->CancelRequest(); 1148 request_handle_->CancelRequest();
1128 return; 1149 return;
1129 } 1150 }
1130 1151
1131 TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS); 1152 TransitionTo(TARGET_PENDING_INTERNAL, UPDATE_OBSERVERS);
1132 1153
1133 BrowserThread::PostTask( 1154 BrowserThread::PostTask(
1134 BrowserThread::FILE, FROM_HERE, 1155 BrowserThread::FILE, FROM_HERE,
1135 base::Bind(&DownloadFile::Initialize, 1156 base::Bind(&DownloadFile::Initialize,
1136 // Safe because we control download file lifetime. 1157 // Safe because we control download file lifetime.
1137 base::Unretained(download_file_.get()), 1158 base::Unretained(download_file_.get()),
1138 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, 1159 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
1139 weak_ptr_factory_.GetWeakPtr()))); 1160 weak_ptr_factory_.GetWeakPtr())));
1140 } 1161 }
1141 1162
1142 void DownloadItemImpl::OnDownloadFileInitialized( 1163 void DownloadItemImpl::OnDownloadFileInitialized(
1143 DownloadInterruptReason result) { 1164 DownloadInterruptReason result) {
1144 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1165 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1166 DCHECK_EQ(state_, TARGET_PENDING_INTERNAL);
1167 DVLOG(20) << __FUNCTION__
1168 << "() result:" << DownloadInterruptReasonToString(result);
1145 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) { 1169 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
1170 // Transition out to TARGET_RESOLVED_INTERNAL since this DownloadItem is
1171 // skipping the download target determination process.
1172 TransitionTo(TARGET_RESOLVED_INTERNAL, DONT_UPDATE_OBSERVERS);
1146 Interrupt(result); 1173 Interrupt(result);
1147 // TODO(rdsmith/asanka): Arguably we should show this in the UI, but 1174 // 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 1175 // 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, 1176 // determination, so we don't know what name to display. OTOH,
1150 // the failure mode of not showing the DI if the file initialization 1177 // 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 1178 // 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 1179 // URLRequest? We'll need to make sure that initialization happens
1153 // properly. Possibly the right thing is to have the UI handle 1180 // properly. Possibly the right thing is to have the UI handle
1154 // this case specially. 1181 // this case specially.
1155 return; 1182 return;
1156 } 1183 }
1157 1184
1158 delegate_->DetermineDownloadTarget( 1185 delegate_->DetermineDownloadTarget(
1159 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined, 1186 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
1160 weak_ptr_factory_.GetWeakPtr())); 1187 weak_ptr_factory_.GetWeakPtr()));
1161 } 1188 }
1162 1189
1163 // Called by delegate_ when the download target path has been 1190 // Called by delegate_ when the download target path has been
1164 // determined. 1191 // determined.
1165 void DownloadItemImpl::OnDownloadTargetDetermined( 1192 void DownloadItemImpl::OnDownloadTargetDetermined(
1166 const base::FilePath& target_path, 1193 const base::FilePath& target_path,
1167 TargetDisposition disposition, 1194 TargetDisposition disposition,
1168 DownloadDangerType danger_type, 1195 DownloadDangerType danger_type,
1169 const base::FilePath& intermediate_path) { 1196 const base::FilePath& intermediate_path) {
1170 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1197 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1198 DCHECK_EQ(state_, TARGET_PENDING_INTERNAL);
1171 1199
1172 // If the |target_path| is empty, then we consider this download to be 1200 // If the |target_path| is empty, then we consider this download to be
1173 // canceled. 1201 // canceled.
1174 if (target_path.empty()) { 1202 if (target_path.empty()) {
1175 Cancel(true); 1203 Cancel(true);
1176 return; 1204 return;
1177 } 1205 }
1178 1206
1179 // TODO(rdsmith,asanka): We are ignoring the possibility that the download 1207 // TODO(rdsmith,asanka): We are ignoring the possibility that the download
1180 // has been interrupted at this point until we finish the intermediate 1208 // 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, 1252 base::Bind(&DownloadFile::RenameAndUniquify,
1225 // Safe because we control download file lifetime. 1253 // Safe because we control download file lifetime.
1226 base::Unretained(download_file_.get()), 1254 base::Unretained(download_file_.get()),
1227 intermediate_path, callback)); 1255 intermediate_path, callback));
1228 } 1256 }
1229 1257
1230 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( 1258 void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
1231 DownloadInterruptReason reason, 1259 DownloadInterruptReason reason,
1232 const base::FilePath& full_path) { 1260 const base::FilePath& full_path) {
1233 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1261 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1262 DCHECK_EQ(state_, TARGET_PENDING_INTERNAL);
1234 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true); 1263 DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
1264 TransitionTo(TARGET_RESOLVED_INTERNAL, DONT_UPDATE_OBSERVERS);
1235 1265
1236 if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) { 1266 if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) {
1237 // Process destination error. If both |reason| and |destination_error_| 1267 // Process destination error. If both |reason| and |destination_error_|
1238 // refer to actual errors, we want to use the |destination_error_| as the 1268 // refer to actual errors, we want to use the |destination_error_| as the
1239 // argument to the Interrupt() routine, as it happened first. 1269 // argument to the Interrupt() routine, as it happened first.
1240 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) 1270 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE)
1241 SetFullPath(full_path); 1271 SetFullPath(full_path);
1242 Interrupt(destination_error_); 1272 Interrupt(destination_error_);
1243 destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE; 1273 destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
1244 } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) { 1274 } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
1245 Interrupt(reason); 1275 Interrupt(reason);
1246 // All file errors result in file deletion above; no need to cleanup. The 1276 // 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 1277 // current_path_ should be empty. Resuming this download will force a
1248 // restart and a re-doing of filename determination. 1278 // restart and a re-doing of filename determination.
1249 DCHECK(current_path_.empty()); 1279 DCHECK(current_path_.empty());
1250 } else { 1280 } else {
1251 SetFullPath(full_path); 1281 SetFullPath(full_path);
1252 UpdateObservers(); 1282 TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS);
1253 MaybeCompleteDownload(); 1283 MaybeCompleteDownload();
1254 } 1284 }
1255 } 1285 }
1256 1286
1257 // When SavePackage downloads MHTML to GData (see 1287 // When SavePackage downloads MHTML to GData (see
1258 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it 1288 // SavePackageFilePickerChromeOS), GData calls MaybeCompleteDownload() like it
1259 // does for non-SavePackage downloads, but SavePackage downloads never satisfy 1289 // does for non-SavePackage downloads, but SavePackage downloads never satisfy
1260 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls 1290 // IsDownloadReadyForCompletion(). GDataDownloadObserver manually calls
1261 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage 1291 // DownloadItem::UpdateObservers() when the upload completes so that SavePackage
1262 // notices that the upload has completed and runs its normal Finish() pathway. 1292 // notices that the upload has completed and runs its normal Finish() pathway.
1263 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes 1293 // MaybeCompleteDownload() is never the mechanism by which SavePackage completes
1264 // downloads. SavePackage always uses its own Finish() to mark downloads 1294 // downloads. SavePackage always uses its own Finish() to mark downloads
1265 // complete. 1295 // complete.
1266 void DownloadItemImpl::MaybeCompleteDownload() { 1296 void DownloadItemImpl::MaybeCompleteDownload() {
1267 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1297 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1268 DCHECK(!is_save_package_download_); 1298 DCHECK(!is_save_package_download_);
1269 1299
1270 if (!IsDownloadReadyForCompletion( 1300 if (!IsDownloadReadyForCompletion(
1271 base::Bind(&DownloadItemImpl::MaybeCompleteDownload, 1301 base::Bind(&DownloadItemImpl::MaybeCompleteDownload,
1272 weak_ptr_factory_.GetWeakPtr()))) 1302 weak_ptr_factory_.GetWeakPtr())))
1273 return; 1303 return;
1274 1304
1275 // TODO(rdsmith): DCHECK that we only pass through this point 1305 // 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 1306 // 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_); 1307 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
1282 DCHECK(!IsDangerous()); 1308 DCHECK(!IsDangerous());
1283 DCHECK(all_data_saved_); 1309 DCHECK(all_data_saved_);
1284 1310
1285 OnDownloadCompleting(); 1311 OnDownloadCompleting();
1286 } 1312 }
1287 1313
1288 // Called by MaybeCompleteDownload() when it has determined that the download 1314 // Called by MaybeCompleteDownload() when it has determined that the download
1289 // is ready for completion. 1315 // is ready for completion.
1290 void DownloadItemImpl::OnDownloadCompleting() { 1316 void DownloadItemImpl::OnDownloadCompleting() {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1349 1375
1350 DCHECK(target_path_ == full_path); 1376 DCHECK(target_path_ == full_path);
1351 1377
1352 if (full_path != current_path_) { 1378 if (full_path != current_path_) {
1353 // full_path is now the current and target file path. 1379 // full_path is now the current and target file path.
1354 DCHECK(!full_path.empty()); 1380 DCHECK(!full_path.empty());
1355 SetFullPath(full_path); 1381 SetFullPath(full_path);
1356 } 1382 }
1357 1383
1358 // Complete the download and release the DownloadFile. 1384 // Complete the download and release the DownloadFile.
1359 DCHECK(download_file_.get()); 1385 DCHECK(download_file_);
1360 ReleaseDownloadFile(false); 1386 ReleaseDownloadFile(false);
1361 1387
1362 // We're not completely done with the download item yet, but at this 1388 // 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, 1389 // 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 1390 // though it's not clear how they could happen) after this point will be
1365 // ignored. 1391 // ignored.
1366 TransitionTo(COMPLETING_INTERNAL, DONT_UPDATE_OBSERVERS); 1392 TransitionTo(COMPLETING_INTERNAL, DONT_UPDATE_OBSERVERS);
1367 1393
1368 if (delegate_->ShouldOpenDownload( 1394 if (delegate_->ShouldOpenDownload(
1369 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened, 1395 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); 1449 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
1424 Interrupt(interrupt_reason); 1450 Interrupt(interrupt_reason);
1425 } 1451 }
1426 1452
1427 // **** End of Download progression cascade 1453 // **** End of Download progression cascade
1428 1454
1429 // An error occurred somewhere. 1455 // An error occurred somewhere.
1430 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { 1456 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
1431 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1457 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1432 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason); 1458 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason);
1459 DVLOG(20) << __FUNCTION__
1460 << "() reason:" << DownloadInterruptReasonToString(reason)
1461 << " this=" << DebugString(true);
1433 1462
1434 // Somewhat counter-intuitively, it is possible for us to receive an 1463 // Somewhat counter-intuitively, it is possible for us to receive an
1435 // interrupt after we've already been interrupted. The generation of 1464 // interrupt after we've already been interrupted. The generation of
1436 // interrupts from the file thread Renames and the generation of 1465 // interrupts from the file thread Renames and the generation of
1437 // interrupts from disk writes go through two different mechanisms (driven 1466 // interrupts from disk writes go through two different mechanisms (driven
1438 // by rename requests from UI thread and by write requests from IO thread, 1467 // 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, 1468 // 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 1469 // this is the place where the races collide. It's also possible for
1441 // interrupts to race with cancels. 1470 // interrupts to race with cancels.
1471 switch (state_) {
1472 case CANCELLED_INTERNAL:
1473 // If the download is already cancelled, then there's no point in
1474 // transitioning out to interrupted.
1475 case COMPLETING_INTERNAL:
1476 case COMPLETE_INTERNAL:
1477 // Already complete.
1478 return;
1442 1479
1443 // Whatever happens, the first one to hit the UI thread wins. 1480 case INITIAL_INTERNAL:
1444 if (state_ != IN_PROGRESS_INTERNAL && state_ != RESUMING_INTERNAL) 1481 case MAX_DOWNLOAD_INTERNAL_STATE:
1445 return; 1482 NOTREACHED();
1483 return;
1446 1484
1447 last_reason_ = reason; 1485 case TARGET_PENDING_INTERNAL:
1486 case TARGET_RESOLVED_INTERNAL:
1487 case IN_PROGRESS_INTERNAL:
1488 // last_reason_ needs to be set for GetResumeMode() to work.
1489 last_reason_ = reason;
1448 1490
1449 ResumeMode resume_mode = GetResumeMode(); 1491 if (download_file_) {
1492 ResumeMode resume_mode = GetResumeMode();
1493 ReleaseDownloadFile(resume_mode != RESUME_MODE_IMMEDIATE_CONTINUE &&
1494 resume_mode != RESUME_MODE_USER_CONTINUE);
1495 } else {
1496 // download_file_ will be missing if we get here via
1497 // StealDangerousDownload().
1498 DCHECK_EQ(DOWNLOAD_INTERRUPT_REASON_USER_CANCELED, reason);
asanka 2016/02/12 15:53:37 SavePackage also hits this code path. I removed th
Randy Smith (Not in Mondays) 2016/02/12 17:37:02 It's ok either way, but any reason not to just mak
asanka 2016/02/12 20:21:24 It tipped the scales against the assertion being u
1499 }
1500 break;
1450 1501
1451 if (state_ == IN_PROGRESS_INTERNAL) { 1502 case RESUMING_INTERNAL:
1452 // Cancel (delete file) if: 1503 case INTERRUPTED_INTERNAL:
1453 // 1) we're going to restart. 1504 // The first non-cancel interrupt reason wins in cases where multiple
1454 // 2) Resumption isn't possible (download was cancelled or blocked due to 1505 // things go wrong.
1455 // security restrictions). 1506 if (reason != DOWNLOAD_INTERRUPT_REASON_USER_CANCELED &&
1456 // 3) Resumption isn't enabled. 1507 reason != DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN)
1457 // No point in leaving data around we aren't going to use. 1508 return;
1458 ReleaseDownloadFile(resume_mode == RESUME_MODE_IMMEDIATE_RESTART ||
1459 resume_mode == RESUME_MODE_USER_RESTART ||
1460 resume_mode == RESUME_MODE_INVALID ||
1461 !IsDownloadResumptionEnabled());
1462 1509
1463 // Cancel the originating URL request. 1510 last_reason_ = reason;
1464 request_handle_->CancelRequest(); 1511 if (!current_path_.empty()) {
1465 } else { 1512 // There is no download file and this is transitioning from INTERRUPTED
1466 DCHECK(!download_file_.get()); 1513 // to CANCELLED. The intermediate file is no longer usable, and should
1514 // be deleted.
1515 BrowserThread::PostTask(
1516 BrowserThread::FILE, FROM_HERE,
1517 base::Bind(base::IgnoreResult(&DeleteDownloadedFile),
1518 current_path_));
1519 current_path_.clear();
1520 }
1521 break;
1467 } 1522 }
1468 1523
1469 // Reset all data saved, as even if we did save all the data we're going 1524 // 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. 1525 // 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 1526 // 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 1527 // 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 1528 // 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 1529 // 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 1530 // simply result in a null range request, which would generate a
1476 // request, which would generate a DestinationCompleted() notification 1531 // DestinationCompleted() notification from the DownloadFile, which would
1477 // from the DownloadFile, which would behave properly with setting 1532 // behave properly with setting all_data_saved_ to false here.
1478 // all_data_saved_ to false here.
1479 all_data_saved_ = false; 1533 all_data_saved_ = false;
1480 1534
1481 TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS); 1535 if (request_handle_)
1482 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); 1536 request_handle_->CancelRequest();
1483 if (!GetWebContents())
1484 RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
1485 1537
1486 AutoResumeIfValid(); 1538 if (reason == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED ||
1539 reason == DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN) {
1540 if (IsDangerous()) {
1541 RecordDangerousDownloadDiscard(
1542 reason == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
1543 ? DOWNLOAD_DISCARD_DUE_TO_USER_ACTION
1544 : DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN,
1545 GetDangerType(), GetTargetFilePath());
1546 }
1547
1548 RecordDownloadCount(CANCELLED_COUNT);
1549 TransitionTo(CANCELLED_INTERNAL, DONT_UPDATE_OBSERVERS);
1550 } else {
1551 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
1552 if (!GetWebContents())
1553 RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
1554 TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS);
1555 AutoResumeIfValid();
1556 }
1557
1487 UpdateObservers(); 1558 UpdateObservers();
1488 } 1559 }
1489 1560
1490 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) { 1561 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) {
1491 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1562 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1563 DVLOG(20) << __FUNCTION__ << "() destroy_file:" << destroy_file;
1492 1564
1493 if (destroy_file) { 1565 if (destroy_file) {
1494 BrowserThread::PostTask( 1566 BrowserThread::PostTask(
1495 BrowserThread::FILE, FROM_HERE, 1567 BrowserThread::FILE, FROM_HERE,
1496 // Will be deleted at end of task execution. 1568 // Will be deleted at end of task execution.
1497 base::Bind(&DownloadFileCancel, base::Passed(&download_file_))); 1569 base::Bind(&DownloadFileCancel, base::Passed(&download_file_)));
1498 // Avoid attempting to reuse the intermediate file by clearing out 1570 // Avoid attempting to reuse the intermediate file by clearing out
1499 // current_path_. 1571 // current_path_.
1500 current_path_.clear(); 1572 current_path_.clear();
1501 } else { 1573 } else {
1502 BrowserThread::PostTask( 1574 BrowserThread::PostTask(
1503 BrowserThread::FILE, 1575 BrowserThread::FILE,
1504 FROM_HERE, 1576 FROM_HERE,
1505 base::Bind(base::IgnoreResult(&DownloadFileDetach), 1577 base::Bind(base::IgnoreResult(&DownloadFileDetach),
1506 // Will be deleted at end of task execution. 1578 // Will be deleted at end of task execution.
1507 base::Passed(&download_file_))); 1579 base::Passed(&download_file_)));
1508 } 1580 }
1509 // Don't accept any more messages from the DownloadFile, and null 1581 // Don't accept any more messages from the DownloadFile, and null
1510 // out any previous "all data received". This also breaks links to 1582 // out any previous "all data received". This also breaks links to
1511 // other entities we've given out weak pointers to. 1583 // other entities we've given out weak pointers to.
1512 weak_ptr_factory_.InvalidateWeakPtrs(); 1584 weak_ptr_factory_.InvalidateWeakPtrs();
1513 } 1585 }
1514 1586
1515 bool DownloadItemImpl::IsDownloadReadyForCompletion( 1587 bool DownloadItemImpl::IsDownloadReadyForCompletion(
1516 const base::Closure& state_change_notification) { 1588 const base::Closure& state_change_notification) {
1589 // If the download hasn't progressed to the IN_PROGRESS state, then it's not
1590 // ready for completion.
1591 if (state_ != IN_PROGRESS_INTERNAL)
1592 return false;
1593
1517 // If we don't have all the data, the download is not ready for 1594 // If we don't have all the data, the download is not ready for
1518 // completion. 1595 // completion.
1519 if (!AllDataSaved()) 1596 if (!AllDataSaved())
1520 return false; 1597 return false;
1521 1598
1522 // If the download is dangerous, but not yet validated, it's not ready for 1599 // If the download is dangerous, but not yet validated, it's not ready for
1523 // completion. 1600 // completion.
1524 if (IsDangerous()) 1601 if (IsDangerous())
1525 return false; 1602 return false;
1526 1603
1527 // If the download isn't active (e.g. has been cancelled) it's not 1604 // Invariants for the IN_PROGRESS state. DCHECKs here verify that the
1528 // ready for completion. 1605 // invariants are still true.
1529 if (state_ != IN_PROGRESS_INTERNAL) 1606 DCHECK(!target_path_.empty());
1530 return false; 1607 DCHECK(!current_path_.empty());
1531 1608 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 1609
1542 // Give the delegate a chance to hold up a stop sign. It'll call 1610 // 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. 1611 // use back through the passed callback if it does and that state changes.
1544 if (!delegate_->ShouldCompleteDownload(this, state_change_notification)) 1612 if (!delegate_->ShouldCompleteDownload(this, state_change_notification))
1545 return false; 1613 return false;
1546 1614
1547 return true; 1615 return true;
1548 } 1616 }
1549 1617
1550 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state, 1618 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
1551 ShouldUpdateObservers notify_action) { 1619 ShouldUpdateObservers notify_action) {
1552 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1620 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1553 1621
1554 if (state_ == new_state) 1622 if (state_ == new_state)
1555 return; 1623 return;
1556 1624
1557 DownloadInternalState old_state = state_; 1625 DownloadInternalState old_state = state_;
1558 state_ = new_state; 1626 state_ = new_state;
1559 1627
1628 DCHECK(is_save_package_download_
1629 ? IsValidSavePackageStateTransition(old_state, new_state)
1630 : IsValidStateTransition(old_state, new_state))
1631 << "Invalid state transition from:" << DebugDownloadStateString(old_state)
1632 << " to:" << DebugDownloadStateString(new_state);
1633
1560 switch (state_) { 1634 switch (state_) {
1635 case INITIAL_INTERNAL:
1636 NOTREACHED();
1637 break;
1638
1639 case TARGET_PENDING_INTERNAL:
1640 case TARGET_RESOLVED_INTERNAL:
1641 break;
1642
1643 case IN_PROGRESS_INTERNAL:
1644 DCHECK(!current_path_.empty()) << "Current output path must be known.";
1645 DCHECK(!target_path_.empty()) << "Target path must be known.";
1646 DCHECK(current_path_.DirName() == target_path_.DirName())
1647 << "Current output directory must match target directory.";
1648 DCHECK(download_file_) << "Output file must be owned by download item.";
1649 DCHECK(request_handle_) << "Download source must be active.";
1650 DCHECK(!is_paused_) << "At the time a download enters IN_PROGRESS state, "
1651 "it must not be paused.";
1652 break;
1653
1561 case COMPLETING_INTERNAL: 1654 case COMPLETING_INTERNAL:
1655 DCHECK(all_data_saved_) << "All data must be saved prior to completion.";
1656 DCHECK(!download_file_)
1657 << "Download file must be released prior to completion.";
1658 DCHECK(!target_path_.empty()) << "Target path must be known.";
1659 DCHECK(current_path_ == target_path_)
1660 << "Current output path must match target path.";
1661
1562 bound_net_log_.AddEvent( 1662 bound_net_log_.AddEvent(
1563 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING, 1663 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING,
1564 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_)); 1664 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_));
1565 break; 1665 break;
1666
1566 case COMPLETE_INTERNAL: 1667 case COMPLETE_INTERNAL:
1567 bound_net_log_.AddEvent( 1668 bound_net_log_.AddEvent(
1568 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED, 1669 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED,
1569 base::Bind(&ItemFinishedNetLogCallback, auto_opened_)); 1670 base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
1570 break; 1671 break;
1672
1571 case INTERRUPTED_INTERNAL: 1673 case INTERRUPTED_INTERNAL:
1572 bound_net_log_.AddEvent( 1674 bound_net_log_.AddEvent(
1573 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED, 1675 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED,
1574 base::Bind(&ItemInterruptedNetLogCallback, last_reason_, 1676 base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
1575 received_bytes_, &hash_state_)); 1677 received_bytes_, &hash_state_));
1576 break; 1678 break;
1577 case IN_PROGRESS_INTERNAL: 1679
1578 if (old_state == INTERRUPTED_INTERNAL) { 1680 case RESUMING_INTERNAL:
1579 bound_net_log_.AddEvent( 1681 bound_net_log_.AddEvent(
1580 net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED, 1682 net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
1581 base::Bind(&ItemResumingNetLogCallback, 1683 base::Bind(&ItemResumingNetLogCallback, false, last_reason_,
1582 false, last_reason_, received_bytes_, &hash_state_)); 1684 received_bytes_, &hash_state_));
1583 }
1584 break; 1685 break;
1686
1585 case CANCELLED_INTERNAL: 1687 case CANCELLED_INTERNAL:
1586 bound_net_log_.AddEvent( 1688 bound_net_log_.AddEvent(
1587 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED, 1689 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
1588 base::Bind(&ItemCanceledNetLogCallback, received_bytes_, 1690 base::Bind(&ItemCanceledNetLogCallback, received_bytes_,
1589 &hash_state_)); 1691 &hash_state_));
1590 break; 1692 break;
1591 default: 1693
1694 case MAX_DOWNLOAD_INTERNAL_STATE:
1695 NOTREACHED();
1592 break; 1696 break;
1593 } 1697 }
1594 1698
1595 DVLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true) 1699 DVLOG(20) << " " << __FUNCTION__ << "()"
1596 << " " << InternalToExternalState(old_state) 1700 << " from:" << DebugDownloadStateString(old_state)
1597 << " " << InternalToExternalState(state_); 1701 << " to:" << DebugDownloadStateString(state_)
1702 << " this = " << DebugString(true);
1703 bool is_done =
1704 (state_ == COMPLETE_INTERNAL || state_ == INTERRUPTED_INTERNAL ||
1705 state_ == RESUMING_INTERNAL || state_ == CANCELLED_INTERNAL);
1706 bool was_done =
1707 (old_state == COMPLETE_INTERNAL || old_state == INTERRUPTED_INTERNAL ||
1708 old_state == RESUMING_INTERNAL || old_state == CANCELLED_INTERNAL);
1598 1709
1599 bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
1600 state_ != COMPLETING_INTERNAL);
1601 bool was_done = (old_state != IN_PROGRESS_INTERNAL &&
1602 old_state != COMPLETING_INTERNAL);
1603 // Termination 1710 // Termination
1604 if (is_done && !was_done) 1711 if (is_done && !was_done)
1605 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE); 1712 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
1606 1713
1607 // Resumption 1714 // Resumption
1608 if (was_done && !is_done) { 1715 if (was_done && !is_done) {
1609 std::string file_name(target_path_.BaseName().AsUTF8Unsafe()); 1716 std::string file_name(target_path_.BaseName().AsUTF8Unsafe());
1610 bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, 1717 bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE,
1611 base::Bind(&ItemActivatedNetLogCallback, 1718 base::Bind(&ItemActivatedNetLogCallback,
1612 this, SRC_ACTIVE_DOWNLOAD, 1719 this, SRC_ACTIVE_DOWNLOAD,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1697 1804
1698 download_params->set_file_path(GetFullPath()); 1805 download_params->set_file_path(GetFullPath());
1699 download_params->set_offset(GetReceivedBytes()); 1806 download_params->set_offset(GetReceivedBytes());
1700 download_params->set_hash_state(GetHashState()); 1807 download_params->set_hash_state(GetHashState());
1701 download_params->set_last_modified(GetLastModifiedTime()); 1808 download_params->set_last_modified(GetLastModifiedTime());
1702 download_params->set_etag(GetETag()); 1809 download_params->set_etag(GetETag());
1703 download_params->set_callback( 1810 download_params->set_callback(
1704 base::Bind(&DownloadItemImpl::OnResumeRequestStarted, 1811 base::Bind(&DownloadItemImpl::OnResumeRequestStarted,
1705 weak_ptr_factory_.GetWeakPtr())); 1812 weak_ptr_factory_.GetWeakPtr()));
1706 1813
1814 TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS);
1707 delegate_->ResumeInterruptedDownload(std::move(download_params), GetId()); 1815 delegate_->ResumeInterruptedDownload(std::move(download_params), GetId());
1708 // Just in case we were interrupted while paused. 1816 // Just in case we were interrupted while paused.
1709 is_paused_ = false; 1817 is_paused_ = false;
1710
1711 TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS);
1712 } 1818 }
1713 1819
1714 // static 1820 // static
1715 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( 1821 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
1716 DownloadInternalState internal_state) { 1822 DownloadInternalState internal_state) {
1717 switch (internal_state) { 1823 switch (internal_state) {
1824 case INITIAL_INTERNAL:
1825 case TARGET_PENDING_INTERNAL:
1826 case TARGET_RESOLVED_INTERNAL:
1827 // TODO(asanka): Introduce an externally visible state to distinguish
1828 // between the above states and IN_PROGRESS_INTERNAL. The latter (the
1829 // state where the download is active and has a known target) is the state
1830 // that most external users are interested in.
1718 case IN_PROGRESS_INTERNAL: 1831 case IN_PROGRESS_INTERNAL:
1719 return IN_PROGRESS; 1832 return IN_PROGRESS;
1720 case COMPLETING_INTERNAL: 1833 case COMPLETING_INTERNAL:
1721 return IN_PROGRESS; 1834 return IN_PROGRESS;
1722 case COMPLETE_INTERNAL: 1835 case COMPLETE_INTERNAL:
1723 return COMPLETE; 1836 return COMPLETE;
1724 case CANCELLED_INTERNAL: 1837 case CANCELLED_INTERNAL:
1725 return CANCELLED; 1838 return CANCELLED;
1726 case INTERRUPTED_INTERNAL: 1839 case INTERRUPTED_INTERNAL:
1727 return INTERRUPTED; 1840 return INTERRUPTED;
(...skipping 18 matching lines...) Expand all
1746 case CANCELLED: 1859 case CANCELLED:
1747 return CANCELLED_INTERNAL; 1860 return CANCELLED_INTERNAL;
1748 case INTERRUPTED: 1861 case INTERRUPTED:
1749 return INTERRUPTED_INTERNAL; 1862 return INTERRUPTED_INTERNAL;
1750 default: 1863 default:
1751 NOTREACHED(); 1864 NOTREACHED();
1752 } 1865 }
1753 return MAX_DOWNLOAD_INTERNAL_STATE; 1866 return MAX_DOWNLOAD_INTERNAL_STATE;
1754 } 1867 }
1755 1868
1869 #if DCHECK_IS_ON()
1870 // static
1871 bool DownloadItemImpl::IsValidSavePackageStateTransition(
1872 DownloadInternalState from,
1873 DownloadInternalState to) {
1874 switch (from) {
1875 case INITIAL_INTERNAL:
1876 case TARGET_PENDING_INTERNAL:
1877 case TARGET_RESOLVED_INTERNAL:
1878 case COMPLETING_INTERNAL:
1879 case COMPLETE_INTERNAL:
1880 case INTERRUPTED_INTERNAL:
1881 case RESUMING_INTERNAL:
1882 case CANCELLED_INTERNAL:
1883 return false;
1884
1885 case IN_PROGRESS_INTERNAL:
1886 return to == CANCELLED_INTERNAL || to == COMPLETE_INTERNAL;
1887
1888 case MAX_DOWNLOAD_INTERNAL_STATE:
1889 NOTREACHED();
1890 }
1891 return false;
1892 }
1893
1894 // static
1895 bool DownloadItemImpl::IsValidStateTransition(DownloadInternalState from,
1896 DownloadInternalState to) {
1897 switch (from) {
1898 case INITIAL_INTERNAL:
1899 return to == TARGET_PENDING_INTERNAL || to == INTERRUPTED_INTERNAL;
1900
1901 case TARGET_PENDING_INTERNAL:
1902 return to == TARGET_RESOLVED_INTERNAL || to == CANCELLED_INTERNAL;
1903
1904 case TARGET_RESOLVED_INTERNAL:
1905 return to == IN_PROGRESS_INTERNAL || to == INTERRUPTED_INTERNAL ||
1906 to == CANCELLED_INTERNAL;
1907
1908 case IN_PROGRESS_INTERNAL:
1909 return to == COMPLETING_INTERNAL || to == CANCELLED_INTERNAL ||
1910 to == INTERRUPTED_INTERNAL;
1911
1912 case COMPLETING_INTERNAL:
1913 return to == COMPLETE_INTERNAL;
1914
1915 case COMPLETE_INTERNAL:
1916 return false;
1917
1918 case INTERRUPTED_INTERNAL:
1919 return to == RESUMING_INTERNAL || to == CANCELLED_INTERNAL;
1920
1921 case RESUMING_INTERNAL:
1922 return to == TARGET_PENDING_INTERNAL || to == CANCELLED_INTERNAL;
1923
1924 case CANCELLED_INTERNAL:
1925 return false;
1926
1927 case MAX_DOWNLOAD_INTERNAL_STATE:
1928 NOTREACHED();
1929 }
1930 return false;
1931 return true;
1932 }
1933 #endif // DCHECK_IS_ON()
1934
1756 const char* DownloadItemImpl::DebugDownloadStateString( 1935 const char* DownloadItemImpl::DebugDownloadStateString(
1757 DownloadInternalState state) { 1936 DownloadInternalState state) {
1758 switch (state) { 1937 switch (state) {
1938 case INITIAL_INTERNAL:
1939 return "INITIAL";
1940 case TARGET_PENDING_INTERNAL:
1941 return "TARGET_PENDING";
1942 case TARGET_RESOLVED_INTERNAL:
1943 return "TARGET_RESOLVED";
1759 case IN_PROGRESS_INTERNAL: 1944 case IN_PROGRESS_INTERNAL:
1760 return "IN_PROGRESS"; 1945 return "IN_PROGRESS";
1761 case COMPLETING_INTERNAL: 1946 case COMPLETING_INTERNAL:
1762 return "COMPLETING"; 1947 return "COMPLETING";
1763 case COMPLETE_INTERNAL: 1948 case COMPLETE_INTERNAL:
1764 return "COMPLETE"; 1949 return "COMPLETE";
1765 case CANCELLED_INTERNAL: 1950 case CANCELLED_INTERNAL:
1766 return "CANCELLED"; 1951 return "CANCELLED";
1767 case INTERRUPTED_INTERNAL: 1952 case INTERRUPTED_INTERNAL:
1768 return "INTERRUPTED"; 1953 return "INTERRUPTED";
(...skipping 17 matching lines...) Expand all
1786 case RESUME_MODE_USER_CONTINUE: 1971 case RESUME_MODE_USER_CONTINUE:
1787 return "USER_CONTINUE"; 1972 return "USER_CONTINUE";
1788 case RESUME_MODE_USER_RESTART: 1973 case RESUME_MODE_USER_RESTART:
1789 return "USER_RESTART"; 1974 return "USER_RESTART";
1790 } 1975 }
1791 NOTREACHED() << "Unknown resume mode " << mode; 1976 NOTREACHED() << "Unknown resume mode " << mode;
1792 return "unknown"; 1977 return "unknown";
1793 } 1978 }
1794 1979
1795 } // namespace content 1980 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/download/download_item_impl.h ('k') | content/browser/download/download_item_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698