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

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 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 }
1496 break;
1450 1497
1451 if (state_ == IN_PROGRESS_INTERNAL) { 1498 case RESUMING_INTERNAL:
1452 // Cancel (delete file) if: 1499 case INTERRUPTED_INTERNAL:
1453 // 1) we're going to restart. 1500 // The first non-cancel interrupt reason wins in cases where multiple
1454 // 2) Resumption isn't possible (download was cancelled or blocked due to 1501 // things go wrong.
1455 // security restrictions). 1502 if (reason != DOWNLOAD_INTERRUPT_REASON_USER_CANCELED &&
1456 // 3) Resumption isn't enabled. 1503 reason != DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN)
1457 // No point in leaving data around we aren't going to use. 1504 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 1505
1463 // Cancel the originating URL request. 1506 last_reason_ = reason;
1464 request_handle_->CancelRequest(); 1507 if (!current_path_.empty()) {
1465 } else { 1508 // There is no download file and this is transitioning from INTERRUPTED
1466 DCHECK(!download_file_.get()); 1509 // to CANCELLED. The intermediate file is no longer usable, and should
1510 // be deleted.
1511 BrowserThread::PostTask(
1512 BrowserThread::FILE, FROM_HERE,
1513 base::Bind(base::IgnoreResult(&DeleteDownloadedFile),
1514 current_path_));
1515 current_path_.clear();
1516 }
1517 break;
1467 } 1518 }
1468 1519
1469 // Reset all data saved, as even if we did save all the data we're going 1520 // 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. 1521 // 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 1522 // 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 1523 // 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 1524 // 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 1525 // 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 1526 // simply result in a null range request, which would generate a
1476 // request, which would generate a DestinationCompleted() notification 1527 // DestinationCompleted() notification from the DownloadFile, which would
1477 // from the DownloadFile, which would behave properly with setting 1528 // behave properly with setting all_data_saved_ to false here.
1478 // all_data_saved_ to false here.
1479 all_data_saved_ = false; 1529 all_data_saved_ = false;
1480 1530
1481 TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS); 1531 if (request_handle_)
1482 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); 1532 request_handle_->CancelRequest();
1483 if (!GetWebContents())
1484 RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
1485 1533
1486 AutoResumeIfValid(); 1534 if (reason == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED ||
1535 reason == DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN) {
1536 if (IsDangerous()) {
1537 RecordDangerousDownloadDiscard(
1538 reason == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
1539 ? DOWNLOAD_DISCARD_DUE_TO_USER_ACTION
1540 : DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN,
1541 GetDangerType(), GetTargetFilePath());
1542 }
1543
1544 RecordDownloadCount(CANCELLED_COUNT);
1545 TransitionTo(CANCELLED_INTERNAL, DONT_UPDATE_OBSERVERS);
1546 } else {
1547 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
1548 if (!GetWebContents())
1549 RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
1550 TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS);
1551 AutoResumeIfValid();
1552 }
1553
1487 UpdateObservers(); 1554 UpdateObservers();
1488 } 1555 }
1489 1556
1490 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) { 1557 void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) {
1491 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1558 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1559 DVLOG(20) << __FUNCTION__ << "() destroy_file:" << destroy_file;
1492 1560
1493 if (destroy_file) { 1561 if (destroy_file) {
1494 BrowserThread::PostTask( 1562 BrowserThread::PostTask(
1495 BrowserThread::FILE, FROM_HERE, 1563 BrowserThread::FILE, FROM_HERE,
1496 // Will be deleted at end of task execution. 1564 // Will be deleted at end of task execution.
1497 base::Bind(&DownloadFileCancel, base::Passed(&download_file_))); 1565 base::Bind(&DownloadFileCancel, base::Passed(&download_file_)));
1498 // Avoid attempting to reuse the intermediate file by clearing out 1566 // Avoid attempting to reuse the intermediate file by clearing out
1499 // current_path_. 1567 // current_path_.
1500 current_path_.clear(); 1568 current_path_.clear();
1501 } else { 1569 } else {
1502 BrowserThread::PostTask( 1570 BrowserThread::PostTask(
1503 BrowserThread::FILE, 1571 BrowserThread::FILE,
1504 FROM_HERE, 1572 FROM_HERE,
1505 base::Bind(base::IgnoreResult(&DownloadFileDetach), 1573 base::Bind(base::IgnoreResult(&DownloadFileDetach),
1506 // Will be deleted at end of task execution. 1574 // Will be deleted at end of task execution.
1507 base::Passed(&download_file_))); 1575 base::Passed(&download_file_)));
1508 } 1576 }
1509 // Don't accept any more messages from the DownloadFile, and null 1577 // Don't accept any more messages from the DownloadFile, and null
1510 // out any previous "all data received". This also breaks links to 1578 // out any previous "all data received". This also breaks links to
1511 // other entities we've given out weak pointers to. 1579 // other entities we've given out weak pointers to.
1512 weak_ptr_factory_.InvalidateWeakPtrs(); 1580 weak_ptr_factory_.InvalidateWeakPtrs();
1513 } 1581 }
1514 1582
1515 bool DownloadItemImpl::IsDownloadReadyForCompletion( 1583 bool DownloadItemImpl::IsDownloadReadyForCompletion(
1516 const base::Closure& state_change_notification) { 1584 const base::Closure& state_change_notification) {
1585 // If the download hasn't progressed to the IN_PROGRESS state, then it's not
1586 // ready for completion.
1587 if (state_ != IN_PROGRESS_INTERNAL)
1588 return false;
1589
1517 // If we don't have all the data, the download is not ready for 1590 // If we don't have all the data, the download is not ready for
1518 // completion. 1591 // completion.
1519 if (!AllDataSaved()) 1592 if (!AllDataSaved())
1520 return false; 1593 return false;
1521 1594
1522 // If the download is dangerous, but not yet validated, it's not ready for 1595 // If the download is dangerous, but not yet validated, it's not ready for
1523 // completion. 1596 // completion.
1524 if (IsDangerous()) 1597 if (IsDangerous())
1525 return false; 1598 return false;
1526 1599
1527 // If the download isn't active (e.g. has been cancelled) it's not 1600 // Invariants for the IN_PROGRESS state. DCHECKs here verify that the
1528 // ready for completion. 1601 // invariants are still true.
1529 if (state_ != IN_PROGRESS_INTERNAL) 1602 DCHECK(!target_path_.empty());
1530 return false; 1603 DCHECK(!current_path_.empty());
1531 1604 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 1605
1542 // Give the delegate a chance to hold up a stop sign. It'll call 1606 // 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. 1607 // use back through the passed callback if it does and that state changes.
1544 if (!delegate_->ShouldCompleteDownload(this, state_change_notification)) 1608 if (!delegate_->ShouldCompleteDownload(this, state_change_notification))
1545 return false; 1609 return false;
1546 1610
1547 return true; 1611 return true;
1548 } 1612 }
1549 1613
1550 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state, 1614 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
1551 ShouldUpdateObservers notify_action) { 1615 ShouldUpdateObservers notify_action) {
1552 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1616 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1553 1617
1554 if (state_ == new_state) 1618 if (state_ == new_state)
1555 return; 1619 return;
1556 1620
1557 DownloadInternalState old_state = state_; 1621 DownloadInternalState old_state = state_;
1558 state_ = new_state; 1622 state_ = new_state;
1559 1623
1624 DCHECK(is_save_package_download_
1625 ? IsValidSavePackageStateTransition(old_state, new_state)
1626 : IsValidStateTransition(old_state, new_state))
1627 << "Invalid state transition from:" << DebugDownloadStateString(old_state)
1628 << " to:" << DebugDownloadStateString(new_state);
1629
1560 switch (state_) { 1630 switch (state_) {
1631 case INITIAL_INTERNAL:
1632 NOTREACHED();
1633 break;
1634
1635 case TARGET_PENDING_INTERNAL:
1636 case TARGET_RESOLVED_INTERNAL:
1637 break;
1638
1639 case IN_PROGRESS_INTERNAL:
1640 DCHECK(!current_path_.empty()) << "Current output path must be known.";
1641 DCHECK(!target_path_.empty()) << "Target path must be known.";
1642 DCHECK(current_path_.DirName() == target_path_.DirName())
1643 << "Current output directory must match target directory.";
1644 DCHECK(download_file_) << "Output file must be owned by download item.";
1645 DCHECK(request_handle_) << "Download source must be active.";
1646 DCHECK(!is_paused_) << "At the time a download enters IN_PROGRESS state, "
1647 "it must not be paused.";
1648 break;
1649
1561 case COMPLETING_INTERNAL: 1650 case COMPLETING_INTERNAL:
1651 DCHECK(all_data_saved_) << "All data must be saved prior to completion.";
1652 DCHECK(!download_file_)
1653 << "Download file must be released prior to completion.";
1654 DCHECK(!target_path_.empty()) << "Target path must be known.";
1655 DCHECK(current_path_ == target_path_)
1656 << "Current output path must match target path.";
1657
1562 bound_net_log_.AddEvent( 1658 bound_net_log_.AddEvent(
1563 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING, 1659 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING,
1564 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_)); 1660 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_));
1565 break; 1661 break;
1662
1566 case COMPLETE_INTERNAL: 1663 case COMPLETE_INTERNAL:
1567 bound_net_log_.AddEvent( 1664 bound_net_log_.AddEvent(
1568 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED, 1665 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED,
1569 base::Bind(&ItemFinishedNetLogCallback, auto_opened_)); 1666 base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
1570 break; 1667 break;
1668
1571 case INTERRUPTED_INTERNAL: 1669 case INTERRUPTED_INTERNAL:
1572 bound_net_log_.AddEvent( 1670 bound_net_log_.AddEvent(
1573 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED, 1671 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED,
1574 base::Bind(&ItemInterruptedNetLogCallback, last_reason_, 1672 base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
1575 received_bytes_, &hash_state_)); 1673 received_bytes_, &hash_state_));
1576 break; 1674 break;
1577 case IN_PROGRESS_INTERNAL: 1675
1578 if (old_state == INTERRUPTED_INTERNAL) { 1676 case RESUMING_INTERNAL:
1579 bound_net_log_.AddEvent( 1677 bound_net_log_.AddEvent(
1580 net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED, 1678 net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
1581 base::Bind(&ItemResumingNetLogCallback, 1679 base::Bind(&ItemResumingNetLogCallback, false, last_reason_,
1582 false, last_reason_, received_bytes_, &hash_state_)); 1680 received_bytes_, &hash_state_));
1583 }
1584 break; 1681 break;
1682
1585 case CANCELLED_INTERNAL: 1683 case CANCELLED_INTERNAL:
1586 bound_net_log_.AddEvent( 1684 bound_net_log_.AddEvent(
1587 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED, 1685 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
1588 base::Bind(&ItemCanceledNetLogCallback, received_bytes_, 1686 base::Bind(&ItemCanceledNetLogCallback, received_bytes_,
1589 &hash_state_)); 1687 &hash_state_));
1590 break; 1688 break;
1591 default: 1689
1690 case MAX_DOWNLOAD_INTERNAL_STATE:
1691 NOTREACHED();
1592 break; 1692 break;
1593 } 1693 }
1594 1694
1595 DVLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true) 1695 DVLOG(20) << " " << __FUNCTION__ << "()"
1596 << " " << InternalToExternalState(old_state) 1696 << " from:" << DebugDownloadStateString(old_state)
1597 << " " << InternalToExternalState(state_); 1697 << " to:" << DebugDownloadStateString(state_)
1698 << " this = " << DebugString(true);
1699 bool is_done =
1700 (state_ == COMPLETE_INTERNAL || state_ == INTERRUPTED_INTERNAL ||
1701 state_ == RESUMING_INTERNAL || state_ == CANCELLED_INTERNAL);
1702 bool was_done =
1703 (old_state == COMPLETE_INTERNAL || old_state == INTERRUPTED_INTERNAL ||
1704 old_state == RESUMING_INTERNAL || old_state == CANCELLED_INTERNAL);
1598 1705
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 1706 // Termination
1604 if (is_done && !was_done) 1707 if (is_done && !was_done)
1605 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE); 1708 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
1606 1709
1607 // Resumption 1710 // Resumption
1608 if (was_done && !is_done) { 1711 if (was_done && !is_done) {
1609 std::string file_name(target_path_.BaseName().AsUTF8Unsafe()); 1712 std::string file_name(target_path_.BaseName().AsUTF8Unsafe());
1610 bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, 1713 bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE,
1611 base::Bind(&ItemActivatedNetLogCallback, 1714 base::Bind(&ItemActivatedNetLogCallback,
1612 this, SRC_ACTIVE_DOWNLOAD, 1715 this, SRC_ACTIVE_DOWNLOAD,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1697 1800
1698 download_params->set_file_path(GetFullPath()); 1801 download_params->set_file_path(GetFullPath());
1699 download_params->set_offset(GetReceivedBytes()); 1802 download_params->set_offset(GetReceivedBytes());
1700 download_params->set_hash_state(GetHashState()); 1803 download_params->set_hash_state(GetHashState());
1701 download_params->set_last_modified(GetLastModifiedTime()); 1804 download_params->set_last_modified(GetLastModifiedTime());
1702 download_params->set_etag(GetETag()); 1805 download_params->set_etag(GetETag());
1703 download_params->set_callback( 1806 download_params->set_callback(
1704 base::Bind(&DownloadItemImpl::OnResumeRequestStarted, 1807 base::Bind(&DownloadItemImpl::OnResumeRequestStarted,
1705 weak_ptr_factory_.GetWeakPtr())); 1808 weak_ptr_factory_.GetWeakPtr()));
1706 1809
1810 TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS);
1707 delegate_->ResumeInterruptedDownload(std::move(download_params), GetId()); 1811 delegate_->ResumeInterruptedDownload(std::move(download_params), GetId());
1708 // Just in case we were interrupted while paused. 1812 // Just in case we were interrupted while paused.
1709 is_paused_ = false; 1813 is_paused_ = false;
1710
1711 TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS);
1712 } 1814 }
1713 1815
1714 // static 1816 // static
1715 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( 1817 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
1716 DownloadInternalState internal_state) { 1818 DownloadInternalState internal_state) {
1717 switch (internal_state) { 1819 switch (internal_state) {
1820 case INITIAL_INTERNAL:
1821 case TARGET_PENDING_INTERNAL:
1822 case TARGET_RESOLVED_INTERNAL:
1823 // TODO(asanka): Introduce an externally visible state to distinguish
1824 // between the above states and IN_PROGRESS_INTERNAL. The latter (the
1825 // state where the download is active and has a known target) is the state
1826 // that most external users are interested in.
1718 case IN_PROGRESS_INTERNAL: 1827 case IN_PROGRESS_INTERNAL:
1719 return IN_PROGRESS; 1828 return IN_PROGRESS;
1720 case COMPLETING_INTERNAL: 1829 case COMPLETING_INTERNAL:
1721 return IN_PROGRESS; 1830 return IN_PROGRESS;
1722 case COMPLETE_INTERNAL: 1831 case COMPLETE_INTERNAL:
1723 return COMPLETE; 1832 return COMPLETE;
1724 case CANCELLED_INTERNAL: 1833 case CANCELLED_INTERNAL:
1725 return CANCELLED; 1834 return CANCELLED;
1726 case INTERRUPTED_INTERNAL: 1835 case INTERRUPTED_INTERNAL:
1727 return INTERRUPTED; 1836 return INTERRUPTED;
(...skipping 18 matching lines...) Expand all
1746 case CANCELLED: 1855 case CANCELLED:
1747 return CANCELLED_INTERNAL; 1856 return CANCELLED_INTERNAL;
1748 case INTERRUPTED: 1857 case INTERRUPTED:
1749 return INTERRUPTED_INTERNAL; 1858 return INTERRUPTED_INTERNAL;
1750 default: 1859 default:
1751 NOTREACHED(); 1860 NOTREACHED();
1752 } 1861 }
1753 return MAX_DOWNLOAD_INTERNAL_STATE; 1862 return MAX_DOWNLOAD_INTERNAL_STATE;
1754 } 1863 }
1755 1864
1865 // static
1866 bool DownloadItemImpl::IsValidSavePackageStateTransition(
1867 DownloadInternalState from,
1868 DownloadInternalState to) {
1869 #if DCHECK_IS_ON()
1870 switch (from) {
1871 case INITIAL_INTERNAL:
1872 case TARGET_PENDING_INTERNAL:
1873 case TARGET_RESOLVED_INTERNAL:
1874 case COMPLETING_INTERNAL:
1875 case COMPLETE_INTERNAL:
1876 case INTERRUPTED_INTERNAL:
1877 case RESUMING_INTERNAL:
1878 case CANCELLED_INTERNAL:
1879 return false;
1880
1881 case IN_PROGRESS_INTERNAL:
1882 return to == CANCELLED_INTERNAL || to == COMPLETE_INTERNAL;
1883
1884 case MAX_DOWNLOAD_INTERNAL_STATE:
1885 NOTREACHED();
1886 }
1887 return false;
1888 #else
1889 return true;
1890 #endif
1891 }
1892
1893 // static
1894 bool DownloadItemImpl::IsValidStateTransition(DownloadInternalState from,
1895 DownloadInternalState to) {
1896 #if DCHECK_IS_ON()
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 #else
1932 return true;
1933 #endif // DCHECK_IS_ON()
1934 }
1935
1756 const char* DownloadItemImpl::DebugDownloadStateString( 1936 const char* DownloadItemImpl::DebugDownloadStateString(
1757 DownloadInternalState state) { 1937 DownloadInternalState state) {
1758 switch (state) { 1938 switch (state) {
1939 case INITIAL_INTERNAL:
1940 return "INITIAL";
1941 case TARGET_PENDING_INTERNAL:
1942 return "TARGET_PENDING";
1943 case TARGET_RESOLVED_INTERNAL:
1944 return "TARGET_RESOLVED";
1759 case IN_PROGRESS_INTERNAL: 1945 case IN_PROGRESS_INTERNAL:
1760 return "IN_PROGRESS"; 1946 return "IN_PROGRESS";
1761 case COMPLETING_INTERNAL: 1947 case COMPLETING_INTERNAL:
1762 return "COMPLETING"; 1948 return "COMPLETING";
1763 case COMPLETE_INTERNAL: 1949 case COMPLETE_INTERNAL:
1764 return "COMPLETE"; 1950 return "COMPLETE";
1765 case CANCELLED_INTERNAL: 1951 case CANCELLED_INTERNAL:
1766 return "CANCELLED"; 1952 return "CANCELLED";
1767 case INTERRUPTED_INTERNAL: 1953 case INTERRUPTED_INTERNAL:
1768 return "INTERRUPTED"; 1954 return "INTERRUPTED";
(...skipping 17 matching lines...) Expand all
1786 case RESUME_MODE_USER_CONTINUE: 1972 case RESUME_MODE_USER_CONTINUE:
1787 return "USER_CONTINUE"; 1973 return "USER_CONTINUE";
1788 case RESUME_MODE_USER_RESTART: 1974 case RESUME_MODE_USER_RESTART:
1789 return "USER_RESTART"; 1975 return "USER_RESTART";
1790 } 1976 }
1791 NOTREACHED() << "Unknown resume mode " << mode; 1977 NOTREACHED() << "Unknown resume mode " << mode;
1792 return "unknown"; 1978 return "unknown";
1793 } 1979 }
1794 1980
1795 } // namespace content 1981 } // 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