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

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

Issue 14955002: [Resumption 6/11] Add a RESUMING_INTERNAL state to DownloadItem. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 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 | Annotate | Revision Log
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 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 if (state_ != IN_PROGRESS_INTERNAL || is_paused_) 302 if (state_ != IN_PROGRESS_INTERNAL || is_paused_)
303 return; 303 return;
304 304
305 request_handle_->PauseRequest(); 305 request_handle_->PauseRequest();
306 is_paused_ = true; 306 is_paused_ = true;
307 UpdateObservers(); 307 UpdateObservers();
308 } 308 }
309 309
310 void DownloadItemImpl::Resume() { 310 void DownloadItemImpl::Resume() {
311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
312 switch (state_) {
313 case IN_PROGRESS_INTERNAL:
314 if (!is_paused_)
315 return;
316 request_handle_->ResumeRequest();
317 is_paused_ = false;
318 UpdateObservers();
319 return;
312 320
313 // Ignore irrelevant states. 321 case COMPLETING_INTERNAL:
314 if (state_ == COMPLETE_INTERNAL || 322 case COMPLETE_INTERNAL:
315 state_ == COMPLETING_INTERNAL || 323 case CANCELLED_INTERNAL:
316 state_ == CANCELLED_INTERNAL || 324 case RESUMING_INTERNAL:
317 (state_ == IN_PROGRESS_INTERNAL && !is_paused_)) 325 return;
318 return;
319 326
320 if (state_ == INTERRUPTED_INTERNAL) { 327 case INTERRUPTED_INTERNAL:
321 auto_resume_count_ = 0; // User input resets the counter. 328 auto_resume_count_ = 0; // User input resets the counter.
322 ResumeInterruptedDownload(); 329 ResumeInterruptedDownload();
323 return; 330 return;
331
332 case MAX_DOWNLOAD_INTERNAL_STATE:
333 NOTREACHED();
324 } 334 }
325 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
326
327 request_handle_->ResumeRequest();
328 is_paused_ = false;
329 UpdateObservers();
330 } 335 }
331 336
332 void DownloadItemImpl::Cancel(bool user_cancel) { 337 void DownloadItemImpl::Cancel(bool user_cancel) {
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
334 339
335 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); 340 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
336 if (state_ != IN_PROGRESS_INTERNAL && state_ != INTERRUPTED_INTERNAL) { 341 if (state_ != IN_PROGRESS_INTERNAL &&
337 // Small downloads might be complete before this method has 342 state_ != INTERRUPTED_INTERNAL &&
338 // a chance to run. 343 state_ != RESUMING_INTERNAL) {
344 // Small downloads might be complete before this method has a chance to run.
339 return; 345 return;
340 } 346 }
341 347
342 last_reason_ = user_cancel ? 348 last_reason_ = user_cancel ?
343 DOWNLOAD_INTERRUPT_REASON_USER_CANCELED : 349 DOWNLOAD_INTERRUPT_REASON_USER_CANCELED :
344 DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN; 350 DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
345 351
346 RecordDownloadCount(CANCELLED_COUNT); 352 RecordDownloadCount(CANCELLED_COUNT);
347 353
348 // TODO(rdsmith/benjhayden): Remove condition as part of 354 // TODO(rdsmith/benjhayden): Remove condition as part of
349 // |SavePackage| integration. 355 // |SavePackage| integration.
350 // |download_file_| can be NULL if Interrupt() is called after the 356 // |download_file_| can be NULL if Interrupt() is called after the
351 // download file has been released. 357 // download file has been released.
352 if (!is_save_package_download_ && download_file_) 358 if (!is_save_package_download_ && download_file_)
353 ReleaseDownloadFile(true); 359 ReleaseDownloadFile(true);
354 360
355 if (state_ != INTERRUPTED_INTERNAL) { 361 if (state_ == IN_PROGRESS_INTERNAL) {
356 // Cancel the originating URL request unless it's already been cancelled 362 // Cancel the originating URL request unless it's already been cancelled
357 // by interrupt. 363 // by interrupt.
358 request_handle_->CancelRequest(); 364 request_handle_->CancelRequest();
359 } 365 }
360 366
361 TransitionTo(CANCELLED_INTERNAL); 367 TransitionTo(CANCELLED_INTERNAL);
362 } 368 }
363 369
364 void DownloadItemImpl::Delete(DeleteReason reason) { 370 void DownloadItemImpl::Delete(DeleteReason reason) {
365 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); 371 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
(...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after
1041 scoped_ptr<DownloadFile> file, 1047 scoped_ptr<DownloadFile> file,
1042 scoped_ptr<DownloadRequestHandleInterface> req_handle) { 1048 scoped_ptr<DownloadRequestHandleInterface> req_handle) {
1043 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1049 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1044 DCHECK(!download_file_.get()); 1050 DCHECK(!download_file_.get());
1045 DCHECK(file.get()); 1051 DCHECK(file.get());
1046 DCHECK(req_handle.get()); 1052 DCHECK(req_handle.get());
1047 1053
1048 download_file_ = file.Pass(); 1054 download_file_ = file.Pass();
1049 request_handle_ = req_handle.Pass(); 1055 request_handle_ = req_handle.Pass();
1050 1056
1057 if (IsCancelled()) {
1058 // The download was in the process of resuming when it was cancelled. Don't
1059 // proceed.
1060 ReleaseDownloadFile(true);
1061 request_handle_->CancelRequest();
Randy Smith (Not in Mondays) 2013/05/09 01:00:57 Is there a reason to do this here, rather than abo
asanka 2013/05/09 16:54:33 I may be misreading this comment. The code is try
Randy Smith (Not in Mondays) 2013/05/10 15:00:30 Whoops; the key thing I was spacing on was the las
1062 return;
1063 }
1064
1051 TransitionTo(IN_PROGRESS_INTERNAL); 1065 TransitionTo(IN_PROGRESS_INTERNAL);
1052 1066
1053 last_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE; 1067 last_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE;
1054 1068
1055 BrowserThread::PostTask( 1069 BrowserThread::PostTask(
1056 BrowserThread::FILE, FROM_HERE, 1070 BrowserThread::FILE, FROM_HERE,
1057 base::Bind(&DownloadFile::Initialize, 1071 base::Bind(&DownloadFile::Initialize,
1058 // Safe because we control download file lifetime. 1072 // Safe because we control download file lifetime.
1059 base::Unretained(download_file_.get()), 1073 base::Unretained(download_file_.get()),
1060 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, 1074 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
1324 // we still need to set it auto-opened so that it can be removed from the 1338 // we still need to set it auto-opened so that it can be removed from the
1325 // download shelf. 1339 // download shelf.
1326 if (!IsTemporary()) 1340 if (!IsTemporary())
1327 OpenDownload(); 1341 OpenDownload();
1328 1342
1329 auto_opened_ = true; 1343 auto_opened_ = true;
1330 UpdateObservers(); 1344 UpdateObservers();
1331 } 1345 }
1332 } 1346 }
1333 1347
1348 void DownloadItemImpl::OnResumeRequestStarted(DownloadItem* item,
1349 net::Error error) {
1350 // If |item| is not NULL, then Start() has been called already, and nothing
1351 // more needs to be done here.
1352 if (item) {
1353 DCHECK_EQ(net::OK, error);
1354 DCHECK_EQ(static_cast<DownloadItem*>(this), item);
1355 return;
1356 }
1357 // Otherwise, the request failed without passing through
1358 // DownloadResourceHandler::OnResponseStarted.
1359 if (error == net::OK)
1360 error = net::ERR_FAILED;
1361 DownloadInterruptReason reason =
1362 ConvertNetErrorToInterruptReason(error, DOWNLOAD_INTERRUPT_FROM_NETWORK);
1363 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason);
1364 Interrupt(reason);
1365 }
1366
1334 // **** End of Download progression cascade 1367 // **** End of Download progression cascade
1335 1368
1336 // An error occurred somewhere. 1369 // An error occurred somewhere.
1337 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { 1370 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
1338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1339 1372
1340 // Somewhat counter-intuitively, it is possible for us to receive an 1373 // Somewhat counter-intuitively, it is possible for us to receive an
1341 // interrupt after we've already been interrupted. The generation of 1374 // interrupt after we've already been interrupted. The generation of
1342 // interrupts from the file thread Renames and the generation of 1375 // interrupts from the file thread Renames and the generation of
1343 // interrupts from disk writes go through two different mechanisms (driven 1376 // interrupts from disk writes go through two different mechanisms (driven
1344 // by rename requests from UI thread and by write requests from IO thread, 1377 // by rename requests from UI thread and by write requests from IO thread,
1345 // respectively), and since we choose not to keep state on the File thread, 1378 // respectively), and since we choose not to keep state on the File thread,
1346 // this is the place where the races collide. It's also possible for 1379 // this is the place where the races collide. It's also possible for
1347 // interrupts to race with cancels. 1380 // interrupts to race with cancels.
1348 1381
1349 // Whatever happens, the first one to hit the UI thread wins. 1382 // Whatever happens, the first one to hit the UI thread wins.
1350 if (state_ != IN_PROGRESS_INTERNAL) 1383 if (state_ != IN_PROGRESS_INTERNAL && state_ != RESUMING_INTERNAL)
Randy Smith (Not in Mondays) 2013/05/09 01:00:57 Why should an interrupt fail in RESUMING_INTERNAL
asanka 2013/05/09 16:54:33 RESUMING_INTERNAL -> INTERRUPTED_INTERNAL happens
Randy Smith (Not in Mondays) 2013/05/10 15:00:30 Got it. It was interrupts happening before we got
1351 return; 1384 return;
1352 1385
1353 last_reason_ = reason; 1386 last_reason_ = reason;
1354 1387
1355 ResumeMode resume_mode = GetResumeMode(); 1388 ResumeMode resume_mode = GetResumeMode();
1356 // Cancel (delete file) if we're going to restart; no point in leaving 1389 // Cancel (delete file) if we're going to restart; no point in leaving
1357 // data around we aren't going to use. Also cancel if resumption isn't 1390 // data around we aren't going to use. Also cancel if resumption isn't
1358 // enabled for the same reason. 1391 // enabled for the same reason.
1359 bool resumption_enabled = CommandLine::ForCurrentProcess()->HasSwitch( 1392 bool resumption_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
1360 switches::kEnableDownloadResumption); 1393 switches::kEnableDownloadResumption);
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1553 void DownloadItemImpl::ResumeInterruptedDownload() { 1586 void DownloadItemImpl::ResumeInterruptedDownload() {
1554 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1555 1588
1556 // If the flag for downloads resumption isn't enabled, ignore 1589 // If the flag for downloads resumption isn't enabled, ignore
1557 // this request. 1590 // this request.
1558 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 1591 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1559 if (!command_line.HasSwitch(switches::kEnableDownloadResumption)) 1592 if (!command_line.HasSwitch(switches::kEnableDownloadResumption))
1560 return; 1593 return;
1561 1594
1562 // If we're not interrupted, ignore the request; our caller is drunk. 1595 // If we're not interrupted, ignore the request; our caller is drunk.
1563 if (!IsInterrupted()) 1596 if (state_ != INTERRUPTED_INTERNAL)
1564 return; 1597 return;
1565 1598
1566 // If we can't get a web contents, we can't resume the download. 1599 // If we can't get a web contents, we can't resume the download.
1567 // TODO(rdsmith): Find some alternative web contents to use--this 1600 // TODO(rdsmith): Find some alternative web contents to use--this
1568 // means we can't restart a download if it's a download imported 1601 // means we can't restart a download if it's a download imported
1569 // from the history. 1602 // from the history.
1570 if (!GetWebContents()) 1603 if (!GetWebContents())
1571 return; 1604 return;
1572 1605
1573 // Reset the appropriate state if restarting. 1606 // Reset the appropriate state if restarting.
1574 ResumeMode mode = GetResumeMode(); 1607 ResumeMode mode = GetResumeMode();
1575 if (mode == RESUME_MODE_IMMEDIATE_RESTART || 1608 if (mode == RESUME_MODE_IMMEDIATE_RESTART ||
1576 mode == RESUME_MODE_USER_RESTART) { 1609 mode == RESUME_MODE_USER_RESTART) {
1577 received_bytes_ = 0; 1610 received_bytes_ = 0;
1578 hash_state_ = ""; 1611 hash_state_ = "";
1579 last_modified_time_ = ""; 1612 last_modified_time_ = "";
1580 etag_ = ""; 1613 etag_ = "";
1581 } 1614 }
1582 1615
1583 scoped_ptr<DownloadUrlParameters> download_params( 1616 scoped_ptr<DownloadUrlParameters> download_params(
1584 DownloadUrlParameters::FromWebContents(GetWebContents(), 1617 DownloadUrlParameters::FromWebContents(GetWebContents(),
1585 GetOriginalUrl())); 1618 GetOriginalUrl()));
1586 1619
1587 download_params->set_file_path(GetFullPath()); 1620 download_params->set_file_path(GetFullPath());
1588 download_params->set_offset(GetReceivedBytes()); 1621 download_params->set_offset(GetReceivedBytes());
1589 download_params->set_hash_state(GetHashState()); 1622 download_params->set_hash_state(GetHashState());
1590 download_params->set_last_modified(GetLastModifiedTime()); 1623 download_params->set_last_modified(GetLastModifiedTime());
1591 download_params->set_etag(GetETag()); 1624 download_params->set_etag(GetETag());
1625 download_params->set_callback(
1626 base::Bind(&DownloadItemImpl::OnResumeRequestStarted,
1627 weak_ptr_factory_.GetWeakPtr()));
1592 1628
1593 delegate_->ResumeInterruptedDownload(download_params.Pass(), GetGlobalId()); 1629 delegate_->ResumeInterruptedDownload(download_params.Pass(), GetGlobalId());
1594
1595 // Just in case we were interrupted while paused. 1630 // Just in case we were interrupted while paused.
1596 is_paused_ = false; 1631 is_paused_ = false;
1632
1633 TransitionTo(RESUMING_INTERNAL);
1597 } 1634 }
1598 1635
1599 // static 1636 // static
1600 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( 1637 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
1601 DownloadInternalState internal_state) { 1638 DownloadInternalState internal_state) {
1602 switch (internal_state) { 1639 switch (internal_state) {
1603 case IN_PROGRESS_INTERNAL: 1640 case IN_PROGRESS_INTERNAL:
1604 return IN_PROGRESS; 1641 return IN_PROGRESS;
1605 case COMPLETING_INTERNAL: 1642 case COMPLETING_INTERNAL:
1606 return IN_PROGRESS; 1643 return IN_PROGRESS;
1607 case COMPLETE_INTERNAL: 1644 case COMPLETE_INTERNAL:
1608 return COMPLETE; 1645 return COMPLETE;
1609 case CANCELLED_INTERNAL: 1646 case CANCELLED_INTERNAL:
1610 return CANCELLED; 1647 return CANCELLED;
1611 case INTERRUPTED_INTERNAL: 1648 case INTERRUPTED_INTERNAL:
1612 return INTERRUPTED; 1649 return INTERRUPTED;
1613 default: 1650 case RESUMING_INTERNAL:
1614 NOTREACHED(); 1651 return INTERRUPTED;
1652 case MAX_DOWNLOAD_INTERNAL_STATE:
1653 break;
1615 } 1654 }
1655 NOTREACHED();
1616 return MAX_DOWNLOAD_STATE; 1656 return MAX_DOWNLOAD_STATE;
1617 } 1657 }
1618 1658
1619 // static 1659 // static
1620 DownloadItemImpl::DownloadInternalState 1660 DownloadItemImpl::DownloadInternalState
1621 DownloadItemImpl::ExternalToInternalState( 1661 DownloadItemImpl::ExternalToInternalState(
1622 DownloadState external_state) { 1662 DownloadState external_state) {
1623 switch (external_state) { 1663 switch (external_state) {
1624 case IN_PROGRESS: 1664 case IN_PROGRESS:
1625 return IN_PROGRESS_INTERNAL; 1665 return IN_PROGRESS_INTERNAL;
1626 case COMPLETE: 1666 case COMPLETE:
1627 return COMPLETE_INTERNAL; 1667 return COMPLETE_INTERNAL;
1628 case CANCELLED: 1668 case CANCELLED:
1629 return CANCELLED_INTERNAL; 1669 return CANCELLED_INTERNAL;
1630 case INTERRUPTED: 1670 case INTERRUPTED:
1631 return INTERRUPTED_INTERNAL; 1671 return INTERRUPTED_INTERNAL;
1632 default: 1672 default:
1633 NOTREACHED(); 1673 NOTREACHED();
1634 } 1674 }
1635 return MAX_DOWNLOAD_INTERNAL_STATE; 1675 return MAX_DOWNLOAD_INTERNAL_STATE;
1636 } 1676 }
benjhayden 2013/05/09 14:49:51 Thanks for fixing the above lines, please also ded
asanka 2013/05/09 16:54:33 Ah thanks! Missed that one.
1637 1677
1638 const char* DownloadItemImpl::DebugDownloadStateString( 1678 const char* DownloadItemImpl::DebugDownloadStateString(
1639 DownloadInternalState state) { 1679 DownloadInternalState state) {
1640 switch (state) { 1680 switch (state) {
1641 case IN_PROGRESS_INTERNAL: 1681 case IN_PROGRESS_INTERNAL:
1642 return "IN_PROGRESS"; 1682 return "IN_PROGRESS";
1643 case COMPLETING_INTERNAL: 1683 case COMPLETING_INTERNAL:
1644 return "COMPLETING"; 1684 return "COMPLETING";
1645 case COMPLETE_INTERNAL: 1685 case COMPLETE_INTERNAL:
1646 return "COMPLETE"; 1686 return "COMPLETE";
1647 case CANCELLED_INTERNAL: 1687 case CANCELLED_INTERNAL:
1648 return "CANCELLED"; 1688 return "CANCELLED";
1649 case INTERRUPTED_INTERNAL: 1689 case INTERRUPTED_INTERNAL:
1650 return "INTERRUPTED"; 1690 return "INTERRUPTED";
1651 default: 1691 case RESUMING_INTERNAL:
1652 NOTREACHED() << "Unknown download state " << state; 1692 return "RESUMING";
1653 return "unknown"; 1693 case MAX_DOWNLOAD_INTERNAL_STATE:
1694 break;
1654 }; 1695 };
1696 NOTREACHED() << "Unknown download state " << state;
1697 return "unknown";
1655 } 1698 }
1656 1699
1657 const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) { 1700 const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) {
1658 switch (mode) { 1701 switch (mode) {
1659 case RESUME_MODE_INVALID: 1702 case RESUME_MODE_INVALID:
1660 return "INVALID"; 1703 return "INVALID";
1661 case RESUME_MODE_IMMEDIATE_CONTINUE: 1704 case RESUME_MODE_IMMEDIATE_CONTINUE:
1662 return "IMMEDIATE_CONTINUE"; 1705 return "IMMEDIATE_CONTINUE";
1663 case RESUME_MODE_IMMEDIATE_RESTART: 1706 case RESUME_MODE_IMMEDIATE_RESTART:
1664 return "IMMEDIATE_RESTART"; 1707 return "IMMEDIATE_RESTART";
1665 case RESUME_MODE_USER_CONTINUE: 1708 case RESUME_MODE_USER_CONTINUE:
1666 return "USER_CONTINUE"; 1709 return "USER_CONTINUE";
1667 case RESUME_MODE_USER_RESTART: 1710 case RESUME_MODE_USER_RESTART:
1668 return "USER_RESTART"; 1711 return "USER_RESTART";
1669 } 1712 }
1670 NOTREACHED() << "Unknown resume mode " << mode; 1713 NOTREACHED() << "Unknown resume mode " << mode;
1671 return "unknown"; 1714 return "unknown";
1672 } 1715 }
1673 1716
1674 } // namespace content 1717 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698