| 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 #include "content/browser/download/download_file_impl.h" | 5 #include "content/browser/download/download_file_impl.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 source_stream)); | 397 source_stream)); |
| 398 } | 398 } |
| 399 | 399 |
| 400 if (total_incoming_data_size) | 400 if (total_incoming_data_size) |
| 401 RecordFileThreadReceiveBuffers(num_buffers); | 401 RecordFileThreadReceiveBuffers(num_buffers); |
| 402 | 402 |
| 403 RecordContiguousWriteTime(now - start); | 403 RecordContiguousWriteTime(now - start); |
| 404 | 404 |
| 405 // Take care of communication with our observer. | 405 // Take care of communication with our observer. |
| 406 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { | 406 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { |
| 407 // Error case for both upstream source and file write. | 407 HandleStreamError(source_stream, reason); |
| 408 // Shut down processing and signal an error to our observer. | |
| 409 // Our observer will clean us up. | |
| 410 source_stream->stream_reader()->RegisterCallback(base::Closure()); | |
| 411 weak_factory_.InvalidateWeakPtrs(); | |
| 412 SendUpdate(); // Make info up to date before error. | |
| 413 std::unique_ptr<crypto::SecureHash> hash_state = file_.Finish(); | |
| 414 BrowserThread::PostTask( | |
| 415 BrowserThread::UI, FROM_HERE, | |
| 416 base::Bind(&DownloadDestinationObserver::DestinationError, observer_, | |
| 417 reason, TotalBytesReceived(), base::Passed(&hash_state))); | |
| 418 num_active_streams_--; | |
| 419 } else if (state == ByteStreamReader::STREAM_COMPLETE || should_terminate) { | 408 } else if (state == ByteStreamReader::STREAM_COMPLETE || should_terminate) { |
| 420 // Signal successful completion or termination of the current stream. | 409 // Signal successful completion or termination of the current stream. |
| 421 source_stream->stream_reader()->RegisterCallback(base::Closure()); | 410 source_stream->stream_reader()->RegisterCallback(base::Closure()); |
| 422 source_stream->set_finished(true); | 411 source_stream->set_finished(true); |
| 423 num_active_streams_--; | 412 num_active_streams_--; |
| 424 | 413 |
| 425 // Inform observers. | 414 // Inform observers. |
| 426 SendUpdate(); | 415 SendUpdate(); |
| 427 | 416 |
| 428 // All the stream reader are completed, shut down file IO processing. | 417 // All the stream reader are completed, shut down file IO processing. |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 return false; | 548 return false; |
| 560 } | 549 } |
| 561 DCHECK_EQ(slices_to_download[0].offset, | 550 DCHECK_EQ(slices_to_download[0].offset, |
| 562 stream_for_last_slice->offset() + | 551 stream_for_last_slice->offset() + |
| 563 stream_for_last_slice->bytes_written()); | 552 stream_for_last_slice->bytes_written()); |
| 564 } | 553 } |
| 565 | 554 |
| 566 return true; | 555 return true; |
| 567 } | 556 } |
| 568 | 557 |
| 558 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, |
| 559 DownloadInterruptReason reason) { |
| 560 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 561 source_stream->stream_reader()->RegisterCallback(base::Closure()); |
| 562 source_stream->set_finished(true); |
| 563 num_active_streams_--; |
| 564 |
| 565 bool can_recover_from_error = false; |
| 566 |
| 567 if (is_sparse_file_) { |
| 568 // If a neighboring stream request is available, check if it can help |
| 569 // download all the data left by |source stream| or has already done so. We |
| 570 // want to avoid the situation that a server always fail additional requests |
| 571 // from the client thus causing the initial request and the download going |
| 572 // nowhere. |
| 573 // TODO(qinmin): make all streams half open so that they can recover |
| 574 // failures from their neighbors. |
| 575 SourceStream* preceding_neighbor = FindPrecedingNeighbor(source_stream); |
| 576 while (preceding_neighbor) { |
| 577 int64_t upper_range = source_stream->offset() + source_stream->length(); |
| 578 if ((!preceding_neighbor->is_finished() && |
| 579 (preceding_neighbor->length() == |
| 580 DownloadSaveInfo::kLengthFullContent || |
| 581 preceding_neighbor->offset() + preceding_neighbor->length() >= |
| 582 upper_range)) || |
| 583 (preceding_neighbor->offset() + preceding_neighbor->bytes_written() >= |
| 584 upper_range)) { |
| 585 can_recover_from_error = true; |
| 586 break; |
| 587 } |
| 588 // If the neighbor cannot recover the error and it has already created |
| 589 // a slice, just interrupt the download. |
| 590 if (preceding_neighbor->bytes_written() > 0) |
| 591 break; |
| 592 preceding_neighbor = FindPrecedingNeighbor(preceding_neighbor); |
| 593 } |
| 594 |
| 595 if (can_recover_from_error) { |
| 596 // Since the neighbor stream will download all data downloading from its |
| 597 // offset to source_stream->offset(). Close all other streams in the |
| 598 // middle. |
| 599 for (auto& stream : source_streams_) { |
| 600 if (stream.second->offset() < source_stream->offset() && |
| 601 stream.second->offset() > preceding_neighbor->offset()) { |
| 602 DCHECK_EQ(stream.second->bytes_written(), 0); |
| 603 stream.second->stream_reader()->RegisterCallback(base::Closure()); |
| 604 stream.second->set_finished(true); |
| 605 num_active_streams_--; |
| 606 } |
| 607 } |
| 608 } |
| 609 } |
| 610 |
| 611 SendUpdate(); // Make info up to date before error. |
| 612 |
| 613 if (!can_recover_from_error) { |
| 614 // Error case for both upstream source and file write. |
| 615 // Shut down processing and signal an error to our observer. |
| 616 // Our observer will clean us up. |
| 617 weak_factory_.InvalidateWeakPtrs(); |
| 618 std::unique_ptr<crypto::SecureHash> hash_state = file_.Finish(); |
| 619 BrowserThread::PostTask( |
| 620 BrowserThread::UI, FROM_HERE, |
| 621 base::Bind(&DownloadDestinationObserver::DestinationError, observer_, |
| 622 reason, TotalBytesReceived(), base::Passed(&hash_state))); |
| 623 } |
| 624 } |
| 625 |
| 626 DownloadFileImpl::SourceStream* DownloadFileImpl::FindPrecedingNeighbor( |
| 627 SourceStream* source_stream) { |
| 628 int64_t max_preceding_offset = 0; |
| 629 SourceStream* ret = nullptr; |
| 630 for (auto& stream : source_streams_) { |
| 631 int64_t offset = stream.second->offset(); |
| 632 if (offset < source_stream->offset() && offset >= max_preceding_offset) { |
| 633 ret = stream.second.get(); |
| 634 max_preceding_offset = offset; |
| 635 } |
| 636 } |
| 637 return ret; |
| 638 } |
| 639 |
| 569 DownloadFileImpl::RenameParameters::RenameParameters( | 640 DownloadFileImpl::RenameParameters::RenameParameters( |
| 570 RenameOption option, | 641 RenameOption option, |
| 571 const base::FilePath& new_path, | 642 const base::FilePath& new_path, |
| 572 const RenameCompletionCallback& completion_callback) | 643 const RenameCompletionCallback& completion_callback) |
| 573 : option(option), | 644 : option(option), |
| 574 new_path(new_path), | 645 new_path(new_path), |
| 575 retries_left(kMaxRenameRetries), | 646 retries_left(kMaxRenameRetries), |
| 576 completion_callback(completion_callback) {} | 647 completion_callback(completion_callback) {} |
| 577 | 648 |
| 578 DownloadFileImpl::RenameParameters::~RenameParameters() {} | 649 DownloadFileImpl::RenameParameters::~RenameParameters() {} |
| 579 | 650 |
| 580 } // namespace content | 651 } // namespace content |
| OLD | NEW |