Chromium Code Reviews| Index: content/browser/download/download_file_impl.cc |
| diff --git a/content/browser/download/download_file_impl.cc b/content/browser/download/download_file_impl.cc |
| index eb1ef9bfd59e107735c6b49daf8f34df324f1191..4c06e52ee304bdb96a11aa9369a9a9a7de635a9e 100644 |
| --- a/content/browser/download/download_file_impl.cc |
| +++ b/content/browser/download/download_file_impl.cc |
| @@ -374,17 +374,7 @@ void DownloadFileImpl::StreamActive(SourceStream* source_stream) { |
| // Take care of communication with our observer. |
| if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { |
| - // Error case for both upstream source and file write. |
| - // Shut down processing and signal an error to our observer. |
| - // Our observer will clean us up. |
| - source_stream->stream_reader()->RegisterCallback(base::Closure()); |
| - weak_factory_.InvalidateWeakPtrs(); |
| - SendUpdate(); // Make info up to date before error. |
| - std::unique_ptr<crypto::SecureHash> hash_state = file_.Finish(); |
| - BrowserThread::PostTask( |
| - BrowserThread::UI, FROM_HERE, |
| - base::Bind(&DownloadDestinationObserver::DestinationError, observer_, |
| - reason, TotalBytesReceived(), base::Passed(&hash_state))); |
| + HandleStreamError(source_stream, reason); |
| } else if (state == ByteStreamReader::STREAM_COMPLETE || should_terminate) { |
| // Signal successful completion or termination of the current stream. |
| source_stream->stream_reader()->RegisterCallback(base::Closure()); |
| @@ -515,6 +505,55 @@ bool DownloadFileImpl::IsDownloadCompleted() { |
| return true; |
| } |
| +void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, |
| + DownloadInterruptReason reason) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| + source_stream->stream_reader()->RegisterCallback(base::Closure()); |
| + source_stream->set_finished(true); |
| + |
| + bool can_recover_from_error = false; |
| + |
| + if (is_sparse_file_) { |
| + auto initial_source_stream = source_streams_.find(save_info_->offset); |
|
xingliu
2017/03/18 22:27:34
What if the error is triggered by the initial stre
qinmin
2017/03/20 20:59:21
If the error is trigger by initial stream, set_fin
xingliu
2017/03/20 22:33:33
I see.
David Trainor- moved to gerrit
2017/03/21 17:00:16
Should we just call this stream_iterator or someth
qinmin
2017/03/21 19:29:17
Done.
|
| + DCHECK(initial_source_stream != source_streams_.end()); |
| + SourceStream* initial_stream = initial_source_stream->second.get(); |
| + // If the initial request is alive, check if it can help download all the |
|
David Trainor- moved to gerrit
2017/03/21 17:00:16
Can we add a TODO to figure out allowing adjacent
qinmin
2017/03/21 19:29:17
Done.
|
| + // data left by this source stream. We want to avoid the situation that |
| + // a server always fail additional requests from the client thus causing the |
| + // initial request and the download going nowhere. |
| + if (!initial_stream->is_finished() && |
| + (initial_stream->length() == DownloadSaveInfo::kLengthFullContent || |
| + initial_stream->offset() + initial_stream->length() > |
| + source_stream->offset() + source_stream->length())) { |
| + // The initial stream will download all data downloading from its offset |
|
xingliu
2017/03/18 22:27:34
If there is a new slice added, does the initial sl
qinmin
2017/03/20 20:59:21
No. For example, there are stream A, B, C ordered
xingliu
2017/03/20 22:33:33
sgtm.
David Trainor- moved to gerrit
2017/03/21 17:00:16
Hmm that seems like it might be a really common oc
qinmin
2017/03/21 19:29:17
This will add more complexity to the current logic
David Trainor- moved to gerrit
2017/03/22 03:10:55
Okay I guess it's fine to postpone this for now.
|
| + // to source_stream->offset(). Close all other streams in the middle. |
| + for (auto& stream : source_streams_) { |
| + if (stream.second->offset() < source_stream->offset() && |
| + stream.second.get() != initial_stream) { |
| + DCHECK_EQ(stream.second->bytes_written(), 0); |
|
xingliu
2017/03/18 22:27:34
Is it safe to assume streams in the middle never w
qinmin
2017/03/20 20:59:21
Yes, if a stream in the middle writes something, i
xingliu
2017/03/20 22:33:33
I see.
David Trainor- moved to gerrit
2017/03/21 17:00:16
Who kills the outstanding request if the middle st
xingliu
2017/03/21 17:48:04
DownloadFileImpl and all objects under it will get
David Trainor- moved to gerrit
2017/03/22 03:10:55
Thanks!
|
| + stream.second->stream_reader()->RegisterCallback(base::Closure()); |
| + stream.second->set_finished(true); |
| + } |
| + } |
| + can_recover_from_error = true; |
| + } |
| + } |
| + |
| + SendUpdate(); // Make info up to date before error. |
| + |
| + if (!can_recover_from_error) { |
| + // Error case for both upstream source and file write. |
| + // Shut down processing and signal an error to our observer. |
| + // Our observer will clean us up. |
| + weak_factory_.InvalidateWeakPtrs(); |
|
David Trainor- moved to gerrit
2017/03/21 17:00:16
Should we pull out the shutdown code to a common h
qinmin
2017/03/21 19:29:17
No, we don't have the lines duplicated. It is simi
David Trainor- moved to gerrit
2017/03/22 03:10:55
Yeah makes sense. Thanks
|
| + std::unique_ptr<crypto::SecureHash> hash_state = file_.Finish(); |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + base::Bind(&DownloadDestinationObserver::DestinationError, observer_, |
| + reason, TotalBytesReceived(), base::Passed(&hash_state))); |
|
xingliu
2017/03/20 22:33:33
nit%: Not in this CL, since we allow duplicate IO
xingliu
2017/03/20 22:35:10
make sure it's ok for user to see larger bytes num
qinmin
2017/03/21 19:29:17
This won't happen. TotalBytesReceived is calculate
|
| + } |
| +} |
| + |
| DownloadFileImpl::RenameParameters::RenameParameters( |
| RenameOption option, |
| const base::FilePath& new_path, |