Chromium Code Reviews| 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 30 matching lines...) Expand all Loading... | |
| 41 // initial delay is specified by kInitialRenameRetryDelayMs. | 41 // initial delay is specified by kInitialRenameRetryDelayMs. |
| 42 const int kInitialRenameRetryDelayMs = 200; | 42 const int kInitialRenameRetryDelayMs = 200; |
| 43 | 43 |
| 44 // Number of times a failing rename is retried before giving up. | 44 // Number of times a failing rename is retried before giving up. |
| 45 const int kMaxRenameRetries = 3; | 45 const int kMaxRenameRetries = 3; |
| 46 | 46 |
| 47 // Because DownloadSaveInfo::kLengthFullContent is 0, we should avoid using | 47 // Because DownloadSaveInfo::kLengthFullContent is 0, we should avoid using |
| 48 // 0 for length if we found that a stream can no longer write any data. | 48 // 0 for length if we found that a stream can no longer write any data. |
| 49 const int kNoBytesToWrite = -1; | 49 const int kNoBytesToWrite = -1; |
| 50 | 50 |
| 51 // Default content length limit when the file size is not yet determined. | |
| 52 const int kUnknownContentLengthLimit = -1; | |
| 53 | |
| 51 } // namespace | 54 } // namespace |
| 52 | 55 |
| 53 DownloadFileImpl::SourceStream::SourceStream( | 56 DownloadFileImpl::SourceStream::SourceStream( |
| 54 int64_t offset, | 57 int64_t offset, |
| 55 int64_t length, | 58 int64_t length, |
| 56 std::unique_ptr<ByteStreamReader> stream_reader) | 59 std::unique_ptr<ByteStreamReader> stream_reader) |
| 57 : offset_(offset), | 60 : offset_(offset), |
| 58 length_(length), | 61 length_(length), |
| 59 bytes_written_(0), | 62 bytes_written_(0), |
| 60 finished_(false), | 63 finished_(false), |
| 61 index_(0u), | 64 index_(0u), |
| 62 stream_reader_(std::move(stream_reader)) {} | 65 stream_reader_(std::move(stream_reader)) {} |
| 63 | 66 |
| 64 DownloadFileImpl::SourceStream::~SourceStream() = default; | 67 DownloadFileImpl::SourceStream::~SourceStream() = default; |
| 65 | 68 |
| 66 void DownloadFileImpl::SourceStream::OnWriteBytesToDisk(int64_t bytes_write) { | 69 void DownloadFileImpl::SourceStream::OnWriteBytesToDisk(int64_t bytes_write) { |
| 67 bytes_written_ += bytes_write; | 70 bytes_written_ += bytes_write; |
| 68 } | 71 } |
| 69 | 72 |
| 70 void DownloadFileImpl::SourceStream::TruncateLengthWithWrittenDataBlock( | 73 void DownloadFileImpl::SourceStream::TruncateLengthWithWrittenDataBlock( |
| 71 int64_t offset, | 74 int64_t offset, |
| 72 int64_t bytes_written) { | 75 int64_t bytes_written) { |
| 73 DCHECK_GT(bytes_written, 0); | 76 DCHECK_GT(bytes_written, 0); |
| 74 if (length_ == kNoBytesToWrite) | 77 if (length_ == kNoBytesToWrite) |
| 75 return; | 78 return; |
| 76 | 79 |
| 77 if (offset <= offset_) { | 80 if (offset <= offset_) { |
| 78 if (offset + bytes_written > offset_) | 81 if (offset + bytes_written > offset_) { |
| 79 length_ = kNoBytesToWrite; | 82 length_ = kNoBytesToWrite; |
| 83 finished_ = true; | |
| 84 } | |
| 80 return; | 85 return; |
| 81 } | 86 } |
| 82 | 87 |
| 83 if (length_ == DownloadSaveInfo::kLengthFullContent || | 88 if (length_ == DownloadSaveInfo::kLengthFullContent || |
| 84 length_ > offset - offset_) { | 89 length_ > offset - offset_) { |
| 85 length_ = offset - offset_; | 90 length_ = offset - offset_; |
| 86 } | 91 } |
| 87 } | 92 } |
| 88 | 93 |
| 89 DownloadFileImpl::DownloadFileImpl( | 94 DownloadFileImpl::DownloadFileImpl( |
| 90 std::unique_ptr<DownloadSaveInfo> save_info, | 95 std::unique_ptr<DownloadSaveInfo> save_info, |
| 91 const base::FilePath& default_download_directory, | 96 const base::FilePath& default_download_directory, |
| 92 std::unique_ptr<ByteStreamReader> stream_reader, | 97 std::unique_ptr<ByteStreamReader> stream_reader, |
| 93 const std::vector<DownloadItem::ReceivedSlice>& received_slices, | 98 const std::vector<DownloadItem::ReceivedSlice>& received_slices, |
| 94 const net::NetLogWithSource& download_item_net_log, | 99 const net::NetLogWithSource& download_item_net_log, |
| 95 base::WeakPtr<DownloadDestinationObserver> observer) | 100 base::WeakPtr<DownloadDestinationObserver> observer) |
| 96 : net_log_( | 101 : net_log_( |
| 97 net::NetLogWithSource::Make(download_item_net_log.net_log(), | 102 net::NetLogWithSource::Make(download_item_net_log.net_log(), |
| 98 net::NetLogSourceType::DOWNLOAD_FILE)), | 103 net::NetLogSourceType::DOWNLOAD_FILE)), |
| 99 file_(net_log_), | 104 file_(net_log_), |
| 100 save_info_(std::move(save_info)), | 105 save_info_(std::move(save_info)), |
| 101 default_download_directory_(default_download_directory), | 106 default_download_directory_(default_download_directory), |
| 107 content_length_limit_(kUnknownContentLengthLimit), | |
| 102 bytes_seen_(0), | 108 bytes_seen_(0), |
| 103 num_active_streams_(0), | 109 num_active_streams_(0), |
| 104 record_stream_bandwidth_(true), | 110 record_stream_bandwidth_(true), |
| 105 bytes_seen_with_parallel_streams_(0), | 111 bytes_seen_with_parallel_streams_(0), |
| 106 bytes_seen_without_parallel_streams_(0), | 112 bytes_seen_without_parallel_streams_(0), |
| 107 received_slices_(received_slices), | 113 received_slices_(received_slices), |
| 108 observer_(observer), | 114 observer_(observer), |
| 109 weak_factory_(this) { | 115 weak_factory_(this) { |
| 110 source_streams_[save_info_->offset] = base::MakeUnique<SourceStream>( | 116 source_streams_[save_info_->offset] = base::MakeUnique<SourceStream>( |
| 111 save_info_->offset, save_info_->length, std::move(stream_reader)); | 117 save_info_->offset, save_info_->length, std::move(stream_reader)); |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 337 } | 343 } |
| 338 | 344 |
| 339 void DownloadFileImpl::Detach() { | 345 void DownloadFileImpl::Detach() { |
| 340 file_.Detach(); | 346 file_.Detach(); |
| 341 } | 347 } |
| 342 | 348 |
| 343 void DownloadFileImpl::Cancel() { | 349 void DownloadFileImpl::Cancel() { |
| 344 file_.Cancel(); | 350 file_.Cancel(); |
| 345 } | 351 } |
| 346 | 352 |
| 353 void DownloadFileImpl::SetContentLengthLimit(int64_t limit) { | |
| 354 DCHECK(content_length_limit_ == limit || | |
| 355 content_length_limit_ == kUnknownContentLengthLimit) | |
| 356 << "Content length changed, the download might have updated."; | |
|
xingliu
2017/03/31 23:38:21
nit%: Since content length is the size of the payl
qinmin
2017/04/01 05:20:01
Done.
| |
| 357 | |
| 358 if (limit < content_length_limit_ || | |
| 359 content_length_limit_ == kUnknownContentLengthLimit) { | |
| 360 content_length_limit_ = limit; | |
|
xingliu
2017/03/31 23:38:21
Will we hit the DCHECK above when limit < content_
qinmin
2017/04/01 05:20:02
Yes, it will cause the DCHECK failure.
The DCHECK
xingliu
2017/04/03 16:51:56
I see. sgtm.
| |
| 361 } | |
| 362 | |
| 363 // TODO(qinmin): interrupt the download if the received bytes are larger | |
| 364 // than content length limit. | |
| 365 LOG_IF(ERROR, TotalBytesReceived() > content_length_limit_) | |
| 366 << "Received data is larger than the content length limit."; | |
| 367 } | |
| 368 | |
| 347 const base::FilePath& DownloadFileImpl::FullPath() const { | 369 const base::FilePath& DownloadFileImpl::FullPath() const { |
| 348 return file_.full_path(); | 370 return file_.full_path(); |
| 349 } | 371 } |
| 350 | 372 |
| 351 bool DownloadFileImpl::InProgress() const { | 373 bool DownloadFileImpl::InProgress() const { |
| 352 return file_.in_progress(); | 374 return file_.in_progress(); |
| 353 } | 375 } |
| 354 | 376 |
| 355 void DownloadFileImpl::WasPaused() { | 377 void DownloadFileImpl::WasPaused() { |
| 356 record_stream_bandwidth_ = false; | 378 record_stream_bandwidth_ = false; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 439 | 461 |
| 440 RecordContiguousWriteTime(now - start); | 462 RecordContiguousWriteTime(now - start); |
| 441 | 463 |
| 442 // Take care of communication with our observer. | 464 // Take care of communication with our observer. |
| 443 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { | 465 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { |
| 444 HandleStreamError(source_stream, reason); | 466 HandleStreamError(source_stream, reason); |
| 445 } else if (state == ByteStreamReader::STREAM_COMPLETE || should_terminate) { | 467 } else if (state == ByteStreamReader::STREAM_COMPLETE || should_terminate) { |
| 446 // Signal successful completion or termination of the current stream. | 468 // Signal successful completion or termination of the current stream. |
| 447 source_stream->stream_reader()->RegisterCallback(base::Closure()); | 469 source_stream->stream_reader()->RegisterCallback(base::Closure()); |
| 448 source_stream->set_finished(true); | 470 source_stream->set_finished(true); |
| 471 if (source_stream->length() == DownloadSaveInfo::kLengthFullContent) { | |
| 472 SetContentLengthLimit(source_stream->offset() + | |
| 473 source_stream->bytes_written()); | |
| 474 } | |
| 449 num_active_streams_--; | 475 num_active_streams_--; |
| 450 | 476 |
| 451 // Inform observers. | 477 // Inform observers. |
| 452 SendUpdate(); | 478 SendUpdate(); |
| 453 | 479 |
| 454 // All the stream reader are completed, shut down file IO processing. | 480 // All the stream reader are completed, shut down file IO processing. |
| 455 if (IsDownloadCompleted()) { | 481 if (IsDownloadCompleted()) { |
| 456 RecordFileBandwidth(bytes_seen_, disk_writes_time_, | 482 RecordFileBandwidth(bytes_seen_, disk_writes_time_, |
| 457 base::TimeTicks::Now() - download_start_); | 483 base::TimeTicks::Now() - download_start_); |
| 458 if (IsSparseFile() && record_stream_bandwidth_) { | 484 if (IsSparseFile() && record_stream_bandwidth_) { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 541 source_stream->set_index(source_stream->index() + 1); | 567 source_stream->set_index(source_stream->index() + 1); |
| 542 } else if (source_stream->offset() == offset) { | 568 } else if (source_stream->offset() == offset) { |
| 543 source_stream->set_index(index); | 569 source_stream->set_index(index); |
| 544 } else { | 570 } else { |
| 545 source_stream->TruncateLengthWithWrittenDataBlock(offset, length); | 571 source_stream->TruncateLengthWithWrittenDataBlock(offset, length); |
| 546 } | 572 } |
| 547 } | 573 } |
| 548 } | 574 } |
| 549 | 575 |
| 550 bool DownloadFileImpl::IsDownloadCompleted() { | 576 bool DownloadFileImpl::IsDownloadCompleted() { |
| 551 SourceStream* stream_for_last_slice = nullptr; | |
| 552 int64_t last_slice_offset = 0; | |
| 553 for (auto& stream : source_streams_) { | 577 for (auto& stream : source_streams_) { |
| 554 SourceStream* source_stream = stream.second.get(); | 578 if (!stream.second->is_finished()) |
| 555 if (source_stream->offset() >= last_slice_offset && | |
| 556 source_stream->bytes_written() > 0) { | |
| 557 stream_for_last_slice = source_stream; | |
| 558 last_slice_offset = source_stream->offset(); | |
| 559 } | |
| 560 if (!source_stream->is_finished()) | |
| 561 return false; | 579 return false; |
| 562 } | 580 } |
| 563 | 581 |
| 564 if (!IsSparseFile()) | 582 if (!IsSparseFile()) |
| 565 return true; | 583 return true; |
| 566 | 584 |
| 567 // Verify that all the file slices have been downloaded. | 585 // Verify that all the file slices have been downloaded. |
| 568 std::vector<DownloadItem::ReceivedSlice> slices_to_download = | 586 std::vector<DownloadItem::ReceivedSlice> slices_to_download = |
| 569 FindSlicesToDownload(received_slices_); | 587 FindSlicesToDownload(received_slices_); |
| 570 if (slices_to_download.size() > 1) { | 588 if (slices_to_download.size() > 1) { |
| 571 // If there are 1 or more holes in the file, download is not finished. | 589 // If there are 1 or more holes in the file, download is not finished. |
| 572 // Some streams might not have been added to |source_streams_| yet. | 590 // Some streams might not have been added to |source_streams_| yet. |
| 573 return false; | 591 return false; |
| 574 } | 592 } |
| 575 if (stream_for_last_slice) { | 593 return TotalBytesReceived() == content_length_limit_; |
| 576 DCHECK_EQ(slices_to_download[0].received_bytes, | |
| 577 DownloadSaveInfo::kLengthFullContent); | |
| 578 // The last stream should not have a length limit. If it has, it might | |
| 579 // not reach the end of the file. | |
| 580 if (stream_for_last_slice->length() != | |
| 581 DownloadSaveInfo::kLengthFullContent) { | |
| 582 return false; | |
| 583 } | |
| 584 DCHECK_EQ(slices_to_download[0].offset, | |
| 585 stream_for_last_slice->offset() + | |
| 586 stream_for_last_slice->bytes_written()); | |
| 587 } | |
| 588 | |
| 589 return true; | |
| 590 } | 594 } |
| 591 | 595 |
| 592 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, | 596 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, |
| 593 DownloadInterruptReason reason) { | 597 DownloadInterruptReason reason) { |
| 594 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 598 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 595 source_stream->stream_reader()->RegisterCallback(base::Closure()); | 599 source_stream->stream_reader()->RegisterCallback(base::Closure()); |
| 596 source_stream->set_finished(true); | 600 source_stream->set_finished(true); |
| 597 num_active_streams_--; | 601 num_active_streams_--; |
| 598 | 602 |
| 599 bool can_recover_from_error = false; | 603 bool can_recover_from_error = false; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 693 const base::FilePath& new_path, | 697 const base::FilePath& new_path, |
| 694 const RenameCompletionCallback& completion_callback) | 698 const RenameCompletionCallback& completion_callback) |
| 695 : option(option), | 699 : option(option), |
| 696 new_path(new_path), | 700 new_path(new_path), |
| 697 retries_left(kMaxRenameRetries), | 701 retries_left(kMaxRenameRetries), |
| 698 completion_callback(completion_callback) {} | 702 completion_callback(completion_callback) {} |
| 699 | 703 |
| 700 DownloadFileImpl::RenameParameters::~RenameParameters() {} | 704 DownloadFileImpl::RenameParameters::~RenameParameters() {} |
| 701 | 705 |
| 702 } // namespace content | 706 } // namespace content |
| OLD | NEW |