| 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 (length_ == kNoBytesToWrite) |
| 75 return; |
| 76 |
| 77 if (offset <= offset_) { |
| 78 if (offset + bytes_written > offset_) |
| 79 length_ = kNoBytesToWrite; |
| 80 return; |
| 81 } |
| 82 |
| 83 if (length_ == DownloadSaveInfo::kLengthFullContent || |
| 84 length_ > offset - offset_) { |
| 85 length_ = offset - offset_; |
| 86 } |
| 87 } |
| 88 |
| 62 DownloadFileImpl::DownloadFileImpl( | 89 DownloadFileImpl::DownloadFileImpl( |
| 63 std::unique_ptr<DownloadSaveInfo> save_info, | 90 std::unique_ptr<DownloadSaveInfo> save_info, |
| 64 const base::FilePath& default_download_directory, | 91 const base::FilePath& default_download_directory, |
| 65 std::unique_ptr<ByteStreamReader> stream_reader, | 92 std::unique_ptr<ByteStreamReader> stream_reader, |
| 66 const std::vector<DownloadItem::ReceivedSlice>& received_slices, | 93 const std::vector<DownloadItem::ReceivedSlice>& received_slices, |
| 67 const net::NetLogWithSource& download_item_net_log, | 94 const net::NetLogWithSource& download_item_net_log, |
| 68 bool is_sparse_file, | 95 bool is_sparse_file, |
| 69 base::WeakPtr<DownloadDestinationObserver> observer) | 96 base::WeakPtr<DownloadDestinationObserver> observer) |
| 70 : net_log_( | 97 : net_log_( |
| 71 net::NetLogWithSource::Make(download_item_net_log.net_log(), | 98 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, | 181 const char* data, |
| 155 size_t data_len) { | 182 size_t data_len) { |
| 156 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 183 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 157 WillWriteToDisk(data_len); | 184 WillWriteToDisk(data_len); |
| 158 return file_.WriteDataToFile(offset, data, data_len); | 185 return file_.WriteDataToFile(offset, data, data_len); |
| 159 } | 186 } |
| 160 | 187 |
| 161 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, | 188 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, |
| 162 size_t bytes_available_to_write, | 189 size_t bytes_available_to_write, |
| 163 size_t* bytes_to_write) { | 190 size_t* bytes_to_write) { |
| 191 if (source_stream->length() == kNoBytesToWrite) { |
| 192 *bytes_to_write = 0; |
| 193 return true; |
| 194 } |
| 195 |
| 164 // If a new slice finds that its target position has already been written, | 196 // If a new slice finds that its target position has already been written, |
| 165 // terminate the stream. | 197 // terminate the stream. |
| 166 if (source_stream->bytes_written() == 0) { | 198 if (source_stream->bytes_written() == 0) { |
| 167 for (const auto& received_slice : received_slices_) { | 199 for (const auto& received_slice : received_slices_) { |
| 168 if (received_slice.offset <= source_stream->offset() && | 200 if (received_slice.offset <= source_stream->offset() && |
| 169 received_slice.offset + received_slice.received_bytes > | 201 received_slice.offset + received_slice.received_bytes > |
| 170 source_stream->offset()) { | 202 source_stream->offset()) { |
| 171 *bytes_to_write = 0; | 203 *bytes_to_write = 0; |
| 172 return true; | 204 return true; |
| 173 } | 205 } |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 } | 473 } |
| 442 } | 474 } |
| 443 | 475 |
| 444 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { | 476 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { |
| 445 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 477 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 446 ByteStreamReader* stream_reader = source_stream->stream_reader(); | 478 ByteStreamReader* stream_reader = source_stream->stream_reader(); |
| 447 if (stream_reader) { | 479 if (stream_reader) { |
| 448 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, | 480 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, |
| 449 weak_factory_.GetWeakPtr(), | 481 weak_factory_.GetWeakPtr(), |
| 450 source_stream)); | 482 source_stream)); |
| 483 // Truncate |source_stream|'s length if necessary. |
| 484 for (const auto& received_slice : received_slices_) { |
| 485 source_stream->TruncateLengthWithWrittenDataBlock( |
| 486 received_slice.offset, received_slice.received_bytes); |
| 487 } |
| 451 StreamActive(source_stream); | 488 StreamActive(source_stream); |
| 452 num_active_streams_++; | 489 num_active_streams_++; |
| 453 } | 490 } |
| 454 } | 491 } |
| 455 | 492 |
| 456 int64_t DownloadFileImpl::TotalBytesReceived() const { | 493 int64_t DownloadFileImpl::TotalBytesReceived() const { |
| 457 return file_.bytes_so_far(); | 494 return file_.bytes_so_far(); |
| 458 } | 495 } |
| 459 | 496 |
| 460 void DownloadFileImpl::SendUpdate() { | 497 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. | 533 // 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); | 534 bool slice_added = (offset == received_slices_[index].offset); |
| 498 // Update the index of exising SourceStreams. | 535 // Update the index of exising SourceStreams. |
| 499 for (auto& stream : source_streams_) { | 536 for (auto& stream : source_streams_) { |
| 500 SourceStream* source_stream = stream.second.get(); | 537 SourceStream* source_stream = stream.second.get(); |
| 501 if (source_stream->offset() > offset) { | 538 if (source_stream->offset() > offset) { |
| 502 if (slice_added && source_stream->bytes_written() > 0) | 539 if (slice_added && source_stream->bytes_written() > 0) |
| 503 source_stream->set_index(source_stream->index() + 1); | 540 source_stream->set_index(source_stream->index() + 1); |
| 504 } else if (source_stream->offset() == offset) { | 541 } else if (source_stream->offset() == offset) { |
| 505 source_stream->set_index(index); | 542 source_stream->set_index(index); |
| 506 } else if (source_stream->length() == | 543 } else { |
| 507 DownloadSaveInfo::kLengthFullContent || | 544 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 } | 545 } |
| 513 } | 546 } |
| 514 } | 547 } |
| 515 | 548 |
| 516 bool DownloadFileImpl::IsDownloadCompleted() { | 549 bool DownloadFileImpl::IsDownloadCompleted() { |
| 517 SourceStream* stream_for_last_slice = nullptr; | 550 SourceStream* stream_for_last_slice = nullptr; |
| 518 int64_t last_slice_offset = 0; | 551 int64_t last_slice_offset = 0; |
| 519 for (auto& stream : source_streams_) { | 552 for (auto& stream : source_streams_) { |
| 520 SourceStream* source_stream = stream.second.get(); | 553 SourceStream* source_stream = stream.second.get(); |
| 521 if (source_stream->offset() >= last_slice_offset && | 554 if (source_stream->offset() >= last_slice_offset && |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 | 590 |
| 558 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, | 591 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, |
| 559 DownloadInterruptReason reason) { | 592 DownloadInterruptReason reason) { |
| 560 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 593 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 561 source_stream->stream_reader()->RegisterCallback(base::Closure()); | 594 source_stream->stream_reader()->RegisterCallback(base::Closure()); |
| 562 source_stream->set_finished(true); | 595 source_stream->set_finished(true); |
| 563 num_active_streams_--; | 596 num_active_streams_--; |
| 564 | 597 |
| 565 bool can_recover_from_error = false; | 598 bool can_recover_from_error = false; |
| 566 | 599 |
| 567 if (is_sparse_file_) { | 600 if (is_sparse_file_ && source_stream->length() != kNoBytesToWrite) { |
| 568 // If a neighboring stream request is available, check if it can help | 601 // 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 | 602 // 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 | 603 // 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 | 604 // from the client thus causing the initial request and the download going |
| 572 // nowhere. | 605 // nowhere. |
| 573 // TODO(qinmin): make all streams half open so that they can recover | 606 // TODO(qinmin): make all streams half open so that they can recover |
| 574 // failures from their neighbors. | 607 // failures from their neighbors. |
| 575 SourceStream* preceding_neighbor = FindPrecedingNeighbor(source_stream); | 608 SourceStream* preceding_neighbor = FindPrecedingNeighbor(source_stream); |
| 576 while (preceding_neighbor) { | 609 while (preceding_neighbor) { |
| 577 int64_t upper_range = source_stream->offset() + source_stream->length(); | 610 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, | 675 const base::FilePath& new_path, |
| 643 const RenameCompletionCallback& completion_callback) | 676 const RenameCompletionCallback& completion_callback) |
| 644 : option(option), | 677 : option(option), |
| 645 new_path(new_path), | 678 new_path(new_path), |
| 646 retries_left(kMaxRenameRetries), | 679 retries_left(kMaxRenameRetries), |
| 647 completion_callback(completion_callback) {} | 680 completion_callback(completion_callback) {} |
| 648 | 681 |
| 649 DownloadFileImpl::RenameParameters::~RenameParameters() {} | 682 DownloadFileImpl::RenameParameters::~RenameParameters() {} |
| 650 | 683 |
| 651 } // namespace content | 684 } // namespace content |
| OLD | NEW |