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 13 matching lines...) Expand all Loading... | |
| 24 #include "crypto/secure_hash.h" | 24 #include "crypto/secure_hash.h" |
| 25 #include "crypto/sha2.h" | 25 #include "crypto/sha2.h" |
| 26 #include "net/base/io_buffer.h" | 26 #include "net/base/io_buffer.h" |
| 27 #include "net/log/net_log.h" | 27 #include "net/log/net_log.h" |
| 28 #include "net/log/net_log_event_type.h" | 28 #include "net/log/net_log_event_type.h" |
| 29 #include "net/log/net_log_source.h" | 29 #include "net/log/net_log_source.h" |
| 30 #include "net/log/net_log_source_type.h" | 30 #include "net/log/net_log_source_type.h" |
| 31 | 31 |
| 32 namespace content { | 32 namespace content { |
| 33 | 33 |
| 34 namespace { | |
| 35 | |
| 34 const int kUpdatePeriodMs = 500; | 36 const int kUpdatePeriodMs = 500; |
| 35 const int kMaxTimeBlockingFileThreadMs = 1000; | 37 const int kMaxTimeBlockingFileThreadMs = 1000; |
| 36 | 38 |
| 37 // These constants control the default retry behavior for failing renames. Each | 39 // These constants control the default retry behavior for failing renames. Each |
| 38 // retry is performed after a delay that is twice the previous delay. The | 40 // retry is performed after a delay that is twice the previous delay. The |
| 39 // initial delay is specified by kInitialRenameRetryDelayMs. | 41 // initial delay is specified by kInitialRenameRetryDelayMs. |
| 40 const int kInitialRenameRetryDelayMs = 200; | 42 const int kInitialRenameRetryDelayMs = 200; |
| 41 | 43 |
| 42 // Number of times a failing rename is retried before giving up. | 44 // Number of times a failing rename is retried before giving up. |
| 43 const int kMaxRenameRetries = 3; | 45 const int kMaxRenameRetries = 3; |
| 44 | 46 |
| 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. | |
| 49 const int kNoBytesToWrite = -1; | |
| 50 | |
| 51 } // namespace | |
| 52 | |
| 45 DownloadFileImpl::SourceStream::SourceStream( | 53 DownloadFileImpl::SourceStream::SourceStream( |
| 46 int64_t offset, | 54 int64_t offset, |
| 47 int64_t length, | 55 int64_t length, |
| 48 std::unique_ptr<ByteStreamReader> stream_reader) | 56 std::unique_ptr<ByteStreamReader> stream_reader) |
| 49 : offset_(offset), | 57 : offset_(offset), |
| 50 length_(length), | 58 length_(length), |
| 51 bytes_written_(0), | 59 bytes_written_(0), |
| 52 finished_(false), | 60 finished_(false), |
| 53 index_(0u), | 61 index_(0u), |
| 54 stream_reader_(std::move(stream_reader)) {} | 62 stream_reader_(std::move(stream_reader)) {} |
| 55 | 63 |
| 56 DownloadFileImpl::SourceStream::~SourceStream() = default; | 64 DownloadFileImpl::SourceStream::~SourceStream() = default; |
| 57 | 65 |
| 58 void DownloadFileImpl::SourceStream::OnWriteBytesToDisk(int64_t bytes_write) { | 66 void DownloadFileImpl::SourceStream::OnWriteBytesToDisk(int64_t bytes_write) { |
| 59 bytes_written_ += bytes_write; | 67 bytes_written_ += bytes_write; |
| 60 } | 68 } |
| 61 | 69 |
| 70 void DownloadFileImpl::SourceStream::TruncateLengthWithWrittenDataBlock( | |
| 71 int64_t offset, | |
| 72 int64_t bytes_written) { | |
| 73 DCHECK_GT(bytes_written, 0); | |
| 74 if (offset < offset_) { | |
|
xingliu
2017/03/24 19:13:47
nit%: Should we also do it when offset == offset_
qinmin
2017/03/24 20:39:01
Done. == is originally captured in the next if blo
| |
| 75 if (offset + bytes_written > offset_) | |
|
xingliu
2017/03/24 19:13:47
nit%: what about if (..&& ..)
qinmin
2017/03/24 20:39:01
No, we want to early return here if offset < offse
xingliu
2017/03/24 21:14:08
My bad, I see.
| |
| 76 length_ = kNoBytesToWrite; | |
| 77 return; | |
| 78 } | |
| 79 | |
| 80 if (length_ == DownloadSaveInfo::kLengthFullContent || | |
| 81 length_ > offset - offset_) { | |
| 82 length_ = offset - offset; | |
|
xingliu
2017/03/24 19:13:47
should it be (offset_ - offset) ?
Also if length_
qinmin
2017/03/24 20:39:01
No, (offset_-offset) is negative in in this if blo
xingliu
2017/03/24 21:14:08
offset - offset is always 0, I think we are trying
qinmin
2017/03/24 21:38:31
should be offset-offset_, fixed.
| |
| 83 // Because DownloadSaveInfo::kLengthFullContent is 0, we should avoid using | |
| 84 // 0 here. | |
| 85 if (length_ == 0) | |
| 86 length_ = kNoBytesToWrite; | |
| 87 } | |
| 88 } | |
| 89 | |
| 62 DownloadFileImpl::DownloadFileImpl( | 90 DownloadFileImpl::DownloadFileImpl( |
| 63 std::unique_ptr<DownloadSaveInfo> save_info, | 91 std::unique_ptr<DownloadSaveInfo> save_info, |
| 64 const base::FilePath& default_download_directory, | 92 const base::FilePath& default_download_directory, |
| 65 std::unique_ptr<ByteStreamReader> stream_reader, | 93 std::unique_ptr<ByteStreamReader> stream_reader, |
| 66 const std::vector<DownloadItem::ReceivedSlice>& received_slices, | 94 const std::vector<DownloadItem::ReceivedSlice>& received_slices, |
| 67 const net::NetLogWithSource& download_item_net_log, | 95 const net::NetLogWithSource& download_item_net_log, |
| 68 bool is_sparse_file, | 96 bool is_sparse_file, |
| 69 base::WeakPtr<DownloadDestinationObserver> observer) | 97 base::WeakPtr<DownloadDestinationObserver> observer) |
| 70 : net_log_( | 98 : net_log_( |
| 71 net::NetLogWithSource::Make(download_item_net_log.net_log(), | 99 net::NetLogWithSource::Make(download_item_net_log.net_log(), |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 const char* data, | 182 const char* data, |
| 155 size_t data_len) { | 183 size_t data_len) { |
| 156 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 184 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 157 WillWriteToDisk(data_len); | 185 WillWriteToDisk(data_len); |
| 158 return file_.WriteDataToFile(offset, data, data_len); | 186 return file_.WriteDataToFile(offset, data, data_len); |
| 159 } | 187 } |
| 160 | 188 |
| 161 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, | 189 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, |
| 162 size_t bytes_available_to_write, | 190 size_t bytes_available_to_write, |
| 163 size_t* bytes_to_write) { | 191 size_t* bytes_to_write) { |
| 192 if (source_stream->length() == kNoBytesToWrite) { | |
| 193 *bytes_to_write = 0; | |
| 194 return true; | |
| 195 } | |
| 196 | |
| 164 // If a new slice finds that its target position has already been written, | 197 // If a new slice finds that its target position has already been written, |
| 165 // terminate the stream. | 198 // terminate the stream. |
| 166 if (source_stream->bytes_written() == 0) { | 199 if (source_stream->bytes_written() == 0) { |
| 167 for (const auto& received_slice : received_slices_) { | 200 for (const auto& received_slice : received_slices_) { |
| 168 if (received_slice.offset <= source_stream->offset() && | 201 if (received_slice.offset <= source_stream->offset() && |
| 169 received_slice.offset + received_slice.received_bytes > | 202 received_slice.offset + received_slice.received_bytes > |
| 170 source_stream->offset()) { | 203 source_stream->offset()) { |
| 171 *bytes_to_write = 0; | 204 *bytes_to_write = 0; |
| 172 return true; | 205 return true; |
| 173 } | 206 } |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 441 } | 474 } |
| 442 } | 475 } |
| 443 | 476 |
| 444 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { | 477 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { |
| 445 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 478 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 446 ByteStreamReader* stream_reader = source_stream->stream_reader(); | 479 ByteStreamReader* stream_reader = source_stream->stream_reader(); |
| 447 if (stream_reader) { | 480 if (stream_reader) { |
| 448 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, | 481 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, |
| 449 weak_factory_.GetWeakPtr(), | 482 weak_factory_.GetWeakPtr(), |
| 450 source_stream)); | 483 source_stream)); |
| 484 // Truncate |source_stream|'s length if necessary. | |
| 485 for (const auto& received_slice : received_slices_) { | |
| 486 source_stream->TruncateLengthWithWrittenDataBlock( | |
| 487 received_slice.offset, received_slice.received_bytes); | |
| 488 } | |
| 451 StreamActive(source_stream); | 489 StreamActive(source_stream); |
| 452 num_active_streams_++; | 490 num_active_streams_++; |
| 453 } | 491 } |
| 454 } | 492 } |
| 455 | 493 |
| 456 int64_t DownloadFileImpl::TotalBytesReceived() const { | 494 int64_t DownloadFileImpl::TotalBytesReceived() const { |
| 457 return file_.bytes_so_far(); | 495 return file_.bytes_so_far(); |
| 458 } | 496 } |
| 459 | 497 |
| 460 void DownloadFileImpl::SendUpdate() { | 498 void DownloadFileImpl::SendUpdate() { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 496 // Check if the slice is added as a new slice, or merged with an existing one. | 534 // Check if the slice is added as a new slice, or merged with an existing one. |
| 497 bool slice_added = (offset == received_slices_[index].offset); | 535 bool slice_added = (offset == received_slices_[index].offset); |
| 498 // Update the index of exising SourceStreams. | 536 // Update the index of exising SourceStreams. |
| 499 for (auto& stream : source_streams_) { | 537 for (auto& stream : source_streams_) { |
| 500 SourceStream* source_stream = stream.second.get(); | 538 SourceStream* source_stream = stream.second.get(); |
| 501 if (source_stream->offset() > offset) { | 539 if (source_stream->offset() > offset) { |
| 502 if (slice_added && source_stream->bytes_written() > 0) | 540 if (slice_added && source_stream->bytes_written() > 0) |
| 503 source_stream->set_index(source_stream->index() + 1); | 541 source_stream->set_index(source_stream->index() + 1); |
| 504 } else if (source_stream->offset() == offset) { | 542 } else if (source_stream->offset() == offset) { |
| 505 source_stream->set_index(index); | 543 source_stream->set_index(index); |
| 506 } else if (source_stream->length() == | 544 } else { |
| 507 DownloadSaveInfo::kLengthFullContent || | 545 source_stream->TruncateLengthWithWrittenDataBlock(offset, length); |
| 508 source_stream->length() > offset - source_stream->offset()) { | |
| 509 // The newly introduced slice will impact the length of the SourceStreams | |
| 510 // preceding it. | |
| 511 source_stream->set_length(offset - source_stream->offset()); | |
| 512 } | 546 } |
| 513 } | 547 } |
| 514 } | 548 } |
| 515 | 549 |
| 516 bool DownloadFileImpl::IsDownloadCompleted() { | 550 bool DownloadFileImpl::IsDownloadCompleted() { |
| 517 SourceStream* stream_for_last_slice = nullptr; | 551 SourceStream* stream_for_last_slice = nullptr; |
| 518 int64_t last_slice_offset = 0; | 552 int64_t last_slice_offset = 0; |
| 519 for (auto& stream : source_streams_) { | 553 for (auto& stream : source_streams_) { |
| 520 SourceStream* source_stream = stream.second.get(); | 554 SourceStream* source_stream = stream.second.get(); |
| 521 if (source_stream->offset() >= last_slice_offset && | 555 if (source_stream->offset() >= last_slice_offset && |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 557 | 591 |
| 558 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, | 592 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, |
| 559 DownloadInterruptReason reason) { | 593 DownloadInterruptReason reason) { |
| 560 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 594 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 561 source_stream->stream_reader()->RegisterCallback(base::Closure()); | 595 source_stream->stream_reader()->RegisterCallback(base::Closure()); |
| 562 source_stream->set_finished(true); | 596 source_stream->set_finished(true); |
| 563 num_active_streams_--; | 597 num_active_streams_--; |
| 564 | 598 |
| 565 bool can_recover_from_error = false; | 599 bool can_recover_from_error = false; |
| 566 | 600 |
| 567 if (is_sparse_file_) { | 601 if (is_sparse_file_ && source_stream->length() != kNoBytesToWrite) { |
| 568 // If a neighboring stream request is available, check if it can help | 602 // 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 | 603 // 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 | 604 // 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 | 605 // from the client thus causing the initial request and the download going |
| 572 // nowhere. | 606 // nowhere. |
| 573 // TODO(qinmin): make all streams half open so that they can recover | 607 // TODO(qinmin): make all streams half open so that they can recover |
| 574 // failures from their neighbors. | 608 // failures from their neighbors. |
| 575 SourceStream* preceding_neighbor = FindPrecedingNeighbor(source_stream); | 609 SourceStream* preceding_neighbor = FindPrecedingNeighbor(source_stream); |
| 576 while (preceding_neighbor) { | 610 while (preceding_neighbor) { |
| 577 int64_t upper_range = source_stream->offset() + source_stream->length(); | 611 int64_t upper_range = source_stream->offset() + source_stream->length(); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 642 const base::FilePath& new_path, | 676 const base::FilePath& new_path, |
| 643 const RenameCompletionCallback& completion_callback) | 677 const RenameCompletionCallback& completion_callback) |
| 644 : option(option), | 678 : option(option), |
| 645 new_path(new_path), | 679 new_path(new_path), |
| 646 retries_left(kMaxRenameRetries), | 680 retries_left(kMaxRenameRetries), |
| 647 completion_callback(completion_callback) {} | 681 completion_callback(completion_callback) {} |
| 648 | 682 |
| 649 DownloadFileImpl::RenameParameters::~RenameParameters() {} | 683 DownloadFileImpl::RenameParameters::~RenameParameters() {} |
| 650 | 684 |
| 651 } // namespace content | 685 } // namespace content |
| OLD | NEW |