OLD | NEW |
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 Loading... |
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 Loading... |
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(); |
| 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 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1319 // we still need to set it auto-opened so that it can be removed from the | 1333 // we still need to set it auto-opened so that it can be removed from the |
1320 // download shelf. | 1334 // download shelf. |
1321 if (!IsTemporary()) | 1335 if (!IsTemporary()) |
1322 OpenDownload(); | 1336 OpenDownload(); |
1323 | 1337 |
1324 auto_opened_ = true; | 1338 auto_opened_ = true; |
1325 UpdateObservers(); | 1339 UpdateObservers(); |
1326 } | 1340 } |
1327 } | 1341 } |
1328 | 1342 |
| 1343 void DownloadItemImpl::OnResumeRequestStarted(DownloadItem* item, |
| 1344 net::Error error) { |
| 1345 // If |item| is not NULL, then Start() has been called already, and nothing |
| 1346 // more needs to be done here. |
| 1347 if (item) { |
| 1348 DCHECK_EQ(net::OK, error); |
| 1349 DCHECK_EQ(static_cast<DownloadItem*>(this), item); |
| 1350 return; |
| 1351 } |
| 1352 // Otherwise, the request failed without passing through |
| 1353 // DownloadResourceHandler::OnResponseStarted. |
| 1354 if (error == net::OK) |
| 1355 error = net::ERR_FAILED; |
| 1356 DownloadInterruptReason reason = |
| 1357 ConvertNetErrorToInterruptReason(error, DOWNLOAD_INTERRUPT_FROM_NETWORK); |
| 1358 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason); |
| 1359 Interrupt(reason); |
| 1360 } |
| 1361 |
1329 // **** End of Download progression cascade | 1362 // **** End of Download progression cascade |
1330 | 1363 |
1331 // An error occurred somewhere. | 1364 // An error occurred somewhere. |
1332 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { | 1365 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { |
1333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1334 | 1367 |
1335 // Somewhat counter-intuitively, it is possible for us to receive an | 1368 // Somewhat counter-intuitively, it is possible for us to receive an |
1336 // interrupt after we've already been interrupted. The generation of | 1369 // interrupt after we've already been interrupted. The generation of |
1337 // interrupts from the file thread Renames and the generation of | 1370 // interrupts from the file thread Renames and the generation of |
1338 // interrupts from disk writes go through two different mechanisms (driven | 1371 // interrupts from disk writes go through two different mechanisms (driven |
1339 // by rename requests from UI thread and by write requests from IO thread, | 1372 // by rename requests from UI thread and by write requests from IO thread, |
1340 // respectively), and since we choose not to keep state on the File thread, | 1373 // respectively), and since we choose not to keep state on the File thread, |
1341 // this is the place where the races collide. It's also possible for | 1374 // this is the place where the races collide. It's also possible for |
1342 // interrupts to race with cancels. | 1375 // interrupts to race with cancels. |
1343 | 1376 |
1344 // Whatever happens, the first one to hit the UI thread wins. | 1377 // Whatever happens, the first one to hit the UI thread wins. |
1345 if (state_ != IN_PROGRESS_INTERNAL) | 1378 if (state_ != IN_PROGRESS_INTERNAL && state_ != RESUMING_INTERNAL) |
1346 return; | 1379 return; |
1347 | 1380 |
1348 last_reason_ = reason; | 1381 last_reason_ = reason; |
1349 | 1382 |
1350 ResumeMode resume_mode = GetResumeMode(); | 1383 ResumeMode resume_mode = GetResumeMode(); |
1351 // Cancel (delete file) if we're going to restart; no point in leaving | 1384 // Cancel (delete file) if we're going to restart; no point in leaving |
1352 // data around we aren't going to use. Also cancel if resumption isn't | 1385 // data around we aren't going to use. Also cancel if resumption isn't |
1353 // enabled for the same reason. | 1386 // enabled for the same reason. |
1354 bool resumption_enabled = CommandLine::ForCurrentProcess()->HasSwitch( | 1387 bool resumption_enabled = CommandLine::ForCurrentProcess()->HasSwitch( |
1355 switches::kEnableDownloadResumption); | 1388 switches::kEnableDownloadResumption); |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1548 void DownloadItemImpl::ResumeInterruptedDownload() { | 1581 void DownloadItemImpl::ResumeInterruptedDownload() { |
1549 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1582 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1550 | 1583 |
1551 // If the flag for downloads resumption isn't enabled, ignore | 1584 // If the flag for downloads resumption isn't enabled, ignore |
1552 // this request. | 1585 // this request. |
1553 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | 1586 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
1554 if (!command_line.HasSwitch(switches::kEnableDownloadResumption)) | 1587 if (!command_line.HasSwitch(switches::kEnableDownloadResumption)) |
1555 return; | 1588 return; |
1556 | 1589 |
1557 // If we're not interrupted, ignore the request; our caller is drunk. | 1590 // If we're not interrupted, ignore the request; our caller is drunk. |
1558 if (!IsInterrupted()) | 1591 if (state_ != INTERRUPTED_INTERNAL) |
1559 return; | 1592 return; |
1560 | 1593 |
1561 // If we can't get a web contents, we can't resume the download. | 1594 // If we can't get a web contents, we can't resume the download. |
1562 // TODO(rdsmith): Find some alternative web contents to use--this | 1595 // TODO(rdsmith): Find some alternative web contents to use--this |
1563 // means we can't restart a download if it's a download imported | 1596 // means we can't restart a download if it's a download imported |
1564 // from the history. | 1597 // from the history. |
1565 if (!GetWebContents()) | 1598 if (!GetWebContents()) |
1566 return; | 1599 return; |
1567 | 1600 |
1568 // Reset the appropriate state if restarting. | 1601 // Reset the appropriate state if restarting. |
1569 ResumeMode mode = GetResumeMode(); | 1602 ResumeMode mode = GetResumeMode(); |
1570 if (mode == RESUME_MODE_IMMEDIATE_RESTART || | 1603 if (mode == RESUME_MODE_IMMEDIATE_RESTART || |
1571 mode == RESUME_MODE_USER_RESTART) { | 1604 mode == RESUME_MODE_USER_RESTART) { |
1572 received_bytes_ = 0; | 1605 received_bytes_ = 0; |
1573 hash_state_ = ""; | 1606 hash_state_ = ""; |
1574 last_modified_time_ = ""; | 1607 last_modified_time_ = ""; |
1575 etag_ = ""; | 1608 etag_ = ""; |
1576 } | 1609 } |
1577 | 1610 |
1578 scoped_ptr<DownloadUrlParameters> download_params( | 1611 scoped_ptr<DownloadUrlParameters> download_params( |
1579 DownloadUrlParameters::FromWebContents(GetWebContents(), | 1612 DownloadUrlParameters::FromWebContents(GetWebContents(), |
1580 GetOriginalUrl())); | 1613 GetOriginalUrl())); |
1581 | 1614 |
1582 download_params->set_file_path(GetFullPath()); | 1615 download_params->set_file_path(GetFullPath()); |
1583 download_params->set_offset(GetReceivedBytes()); | 1616 download_params->set_offset(GetReceivedBytes()); |
1584 download_params->set_hash_state(GetHashState()); | 1617 download_params->set_hash_state(GetHashState()); |
1585 download_params->set_last_modified(GetLastModifiedTime()); | 1618 download_params->set_last_modified(GetLastModifiedTime()); |
1586 download_params->set_etag(GetETag()); | 1619 download_params->set_etag(GetETag()); |
| 1620 download_params->set_callback( |
| 1621 base::Bind(&DownloadItemImpl::OnResumeRequestStarted, |
| 1622 weak_ptr_factory_.GetWeakPtr())); |
1587 | 1623 |
1588 delegate_->ResumeInterruptedDownload(download_params.Pass(), GetGlobalId()); | 1624 delegate_->ResumeInterruptedDownload(download_params.Pass(), GetGlobalId()); |
1589 | |
1590 // Just in case we were interrupted while paused. | 1625 // Just in case we were interrupted while paused. |
1591 is_paused_ = false; | 1626 is_paused_ = false; |
| 1627 |
| 1628 TransitionTo(RESUMING_INTERNAL); |
1592 } | 1629 } |
1593 | 1630 |
1594 // static | 1631 // static |
1595 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( | 1632 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( |
1596 DownloadInternalState internal_state) { | 1633 DownloadInternalState internal_state) { |
1597 switch (internal_state) { | 1634 switch (internal_state) { |
1598 case IN_PROGRESS_INTERNAL: | 1635 case IN_PROGRESS_INTERNAL: |
1599 return IN_PROGRESS; | 1636 return IN_PROGRESS; |
1600 case COMPLETING_INTERNAL: | 1637 case COMPLETING_INTERNAL: |
1601 return IN_PROGRESS; | 1638 return IN_PROGRESS; |
1602 case COMPLETE_INTERNAL: | 1639 case COMPLETE_INTERNAL: |
1603 return COMPLETE; | 1640 return COMPLETE; |
1604 case CANCELLED_INTERNAL: | 1641 case CANCELLED_INTERNAL: |
1605 return CANCELLED; | 1642 return CANCELLED; |
1606 case INTERRUPTED_INTERNAL: | 1643 case INTERRUPTED_INTERNAL: |
1607 return INTERRUPTED; | 1644 return INTERRUPTED; |
1608 default: | 1645 case RESUMING_INTERNAL: |
1609 NOTREACHED(); | 1646 return INTERRUPTED; |
| 1647 case MAX_DOWNLOAD_INTERNAL_STATE: |
| 1648 break; |
1610 } | 1649 } |
| 1650 NOTREACHED(); |
1611 return MAX_DOWNLOAD_STATE; | 1651 return MAX_DOWNLOAD_STATE; |
1612 } | 1652 } |
1613 | 1653 |
1614 // static | 1654 // static |
1615 DownloadItemImpl::DownloadInternalState | 1655 DownloadItemImpl::DownloadInternalState |
1616 DownloadItemImpl::ExternalToInternalState( | 1656 DownloadItemImpl::ExternalToInternalState( |
1617 DownloadState external_state) { | 1657 DownloadState external_state) { |
1618 switch (external_state) { | 1658 switch (external_state) { |
1619 case IN_PROGRESS: | 1659 case IN_PROGRESS: |
1620 return IN_PROGRESS_INTERNAL; | 1660 return IN_PROGRESS_INTERNAL; |
1621 case COMPLETE: | 1661 case COMPLETE: |
1622 return COMPLETE_INTERNAL; | 1662 return COMPLETE_INTERNAL; |
1623 case CANCELLED: | 1663 case CANCELLED: |
1624 return CANCELLED_INTERNAL; | 1664 return CANCELLED_INTERNAL; |
1625 case INTERRUPTED: | 1665 case INTERRUPTED: |
1626 return INTERRUPTED_INTERNAL; | 1666 return INTERRUPTED_INTERNAL; |
1627 default: | 1667 default: |
1628 NOTREACHED(); | 1668 NOTREACHED(); |
1629 } | 1669 } |
1630 return MAX_DOWNLOAD_INTERNAL_STATE; | 1670 return MAX_DOWNLOAD_INTERNAL_STATE; |
1631 } | 1671 } |
1632 | 1672 |
1633 const char* DownloadItemImpl::DebugDownloadStateString( | 1673 const char* DownloadItemImpl::DebugDownloadStateString( |
1634 DownloadInternalState state) { | 1674 DownloadInternalState state) { |
1635 switch (state) { | 1675 switch (state) { |
1636 case IN_PROGRESS_INTERNAL: | 1676 case IN_PROGRESS_INTERNAL: |
1637 return "IN_PROGRESS"; | 1677 return "IN_PROGRESS"; |
1638 case COMPLETING_INTERNAL: | 1678 case COMPLETING_INTERNAL: |
1639 return "COMPLETING"; | 1679 return "COMPLETING"; |
1640 case COMPLETE_INTERNAL: | 1680 case COMPLETE_INTERNAL: |
1641 return "COMPLETE"; | 1681 return "COMPLETE"; |
1642 case CANCELLED_INTERNAL: | 1682 case CANCELLED_INTERNAL: |
1643 return "CANCELLED"; | 1683 return "CANCELLED"; |
1644 case INTERRUPTED_INTERNAL: | 1684 case INTERRUPTED_INTERNAL: |
1645 return "INTERRUPTED"; | 1685 return "INTERRUPTED"; |
1646 default: | 1686 case RESUMING_INTERNAL: |
1647 NOTREACHED() << "Unknown download state " << state; | 1687 return "RESUMING"; |
1648 return "unknown"; | 1688 case MAX_DOWNLOAD_INTERNAL_STATE: |
| 1689 break; |
1649 }; | 1690 }; |
| 1691 NOTREACHED() << "Unknown download state " << state; |
| 1692 return "unknown"; |
1650 } | 1693 } |
1651 | 1694 |
1652 const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) { | 1695 const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) { |
1653 switch (mode) { | 1696 switch (mode) { |
1654 case RESUME_MODE_INVALID: | 1697 case RESUME_MODE_INVALID: |
1655 return "INVALID"; | 1698 return "INVALID"; |
1656 case RESUME_MODE_IMMEDIATE_CONTINUE: | 1699 case RESUME_MODE_IMMEDIATE_CONTINUE: |
1657 return "IMMEDIATE_CONTINUE"; | 1700 return "IMMEDIATE_CONTINUE"; |
1658 case RESUME_MODE_IMMEDIATE_RESTART: | 1701 case RESUME_MODE_IMMEDIATE_RESTART: |
1659 return "IMMEDIATE_RESTART"; | 1702 return "IMMEDIATE_RESTART"; |
1660 case RESUME_MODE_USER_CONTINUE: | 1703 case RESUME_MODE_USER_CONTINUE: |
1661 return "USER_CONTINUE"; | 1704 return "USER_CONTINUE"; |
1662 case RESUME_MODE_USER_RESTART: | 1705 case RESUME_MODE_USER_RESTART: |
1663 return "USER_RESTART"; | 1706 return "USER_RESTART"; |
1664 } | 1707 } |
1665 NOTREACHED() << "Unknown resume mode " << mode; | 1708 NOTREACHED() << "Unknown resume mode " << mode; |
1666 return "unknown"; | 1709 return "unknown"; |
1667 } | 1710 } |
1668 | 1711 |
1669 } // namespace content | 1712 } // namespace content |
OLD | NEW |