| 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" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
| 13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 15 #include "base/values.h" | 15 #include "base/values.h" |
| 16 #include "content/browser/byte_stream.h" | 16 #include "content/browser/byte_stream.h" |
| 17 #include "content/browser/download/download_create_info.h" | 17 #include "content/browser/download/download_create_info.h" |
| 18 #include "content/browser/download/download_destination_observer.h" | 18 #include "content/browser/download/download_destination_observer.h" |
| 19 #include "content/browser/download/download_interrupt_reasons_impl.h" | 19 #include "content/browser/download/download_interrupt_reasons_impl.h" |
| 20 #include "content/browser/download/download_net_log_parameters.h" | 20 #include "content/browser/download/download_net_log_parameters.h" |
| 21 #include "content/browser/download/download_stats.h" | 21 #include "content/browser/download/download_stats.h" |
| 22 #include "content/browser/download/download_task_runner.h" |
| 22 #include "content/browser/download/parallel_download_utils.h" | 23 #include "content/browser/download/parallel_download_utils.h" |
| 23 #include "content/public/browser/browser_thread.h" | 24 #include "content/public/browser/browser_thread.h" |
| 24 #include "crypto/secure_hash.h" | 25 #include "crypto/secure_hash.h" |
| 25 #include "crypto/sha2.h" | 26 #include "crypto/sha2.h" |
| 26 #include "net/base/io_buffer.h" | 27 #include "net/base/io_buffer.h" |
| 27 #include "net/log/net_log.h" | 28 #include "net/log/net_log.h" |
| 28 #include "net/log/net_log_event_type.h" | 29 #include "net/log/net_log_event_type.h" |
| 29 #include "net/log/net_log_source.h" | 30 #include "net/log/net_log_source.h" |
| 30 #include "net/log/net_log_source_type.h" | 31 #include "net/log/net_log_source_type.h" |
| 31 | 32 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 weak_factory_(this) { | 114 weak_factory_(this) { |
| 114 source_streams_[save_info_->offset] = base::MakeUnique<SourceStream>( | 115 source_streams_[save_info_->offset] = base::MakeUnique<SourceStream>( |
| 115 save_info_->offset, save_info_->length, std::move(stream_reader)); | 116 save_info_->offset, save_info_->length, std::move(stream_reader)); |
| 116 | 117 |
| 117 download_item_net_log.AddEvent( | 118 download_item_net_log.AddEvent( |
| 118 net::NetLogEventType::DOWNLOAD_FILE_CREATED, | 119 net::NetLogEventType::DOWNLOAD_FILE_CREATED, |
| 119 net_log_.source().ToEventParametersCallback()); | 120 net_log_.source().ToEventParametersCallback()); |
| 120 net_log_.BeginEvent( | 121 net_log_.BeginEvent( |
| 121 net::NetLogEventType::DOWNLOAD_FILE_ACTIVE, | 122 net::NetLogEventType::DOWNLOAD_FILE_ACTIVE, |
| 122 download_item_net_log.source().ToEventParametersCallback()); | 123 download_item_net_log.source().ToEventParametersCallback()); |
| 124 |
| 125 DETACH_FROM_SEQUENCE(sequence_checker_); |
| 123 } | 126 } |
| 124 | 127 |
| 125 DownloadFileImpl::~DownloadFileImpl() { | 128 DownloadFileImpl::~DownloadFileImpl() { |
| 126 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 129 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 130 |
| 127 net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_ACTIVE); | 131 net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_ACTIVE); |
| 128 } | 132 } |
| 129 | 133 |
| 130 void DownloadFileImpl::Initialize( | 134 void DownloadFileImpl::Initialize( |
| 131 const InitializeCallback& initialize_callback, | 135 const InitializeCallback& initialize_callback, |
| 132 const CancelRequestCallback& cancel_request_callback, | 136 const CancelRequestCallback& cancel_request_callback, |
| 133 const DownloadItem::ReceivedSlices& received_slices, | 137 const DownloadItem::ReceivedSlices& received_slices, |
| 134 bool is_parallelizable) { | 138 bool is_parallelizable) { |
| 135 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 139 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 136 | 140 |
| 137 update_timer_.reset(new base::RepeatingTimer()); | 141 update_timer_.reset(new base::RepeatingTimer()); |
| 138 int64_t bytes_so_far = 0; | 142 int64_t bytes_so_far = 0; |
| 139 cancel_request_callback_ = cancel_request_callback; | 143 cancel_request_callback_ = cancel_request_callback; |
| 140 received_slices_ = received_slices; | 144 received_slices_ = received_slices; |
| 141 if (IsSparseFile()) { | 145 if (IsSparseFile()) { |
| 142 for (const auto& received_slice : received_slices_) { | 146 for (const auto& received_slice : received_slices_) { |
| 143 bytes_so_far += received_slice.received_bytes; | 147 bytes_so_far += received_slice.received_bytes; |
| 144 } | 148 } |
| 145 } else { | 149 } else { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 169 | 173 |
| 170 // Initial pull from the straw from all source streams. | 174 // Initial pull from the straw from all source streams. |
| 171 for (auto& source_stream : source_streams_) | 175 for (auto& source_stream : source_streams_) |
| 172 RegisterAndActivateStream(source_stream.second.get()); | 176 RegisterAndActivateStream(source_stream.second.get()); |
| 173 } | 177 } |
| 174 | 178 |
| 175 void DownloadFileImpl::AddByteStream( | 179 void DownloadFileImpl::AddByteStream( |
| 176 std::unique_ptr<ByteStreamReader> stream_reader, | 180 std::unique_ptr<ByteStreamReader> stream_reader, |
| 177 int64_t offset, | 181 int64_t offset, |
| 178 int64_t length) { | 182 int64_t length) { |
| 179 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 183 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 180 | 184 |
| 181 source_streams_[offset] = | 185 source_streams_[offset] = |
| 182 base::MakeUnique<SourceStream>(offset, length, std::move(stream_reader)); | 186 base::MakeUnique<SourceStream>(offset, length, std::move(stream_reader)); |
| 183 | 187 |
| 184 // There are writers at different offsets now, create the received slices | 188 // There are writers at different offsets now, create the received slices |
| 185 // vector if necessary. | 189 // vector if necessary. |
| 186 if (received_slices_.empty() && TotalBytesReceived() > 0) { | 190 if (received_slices_.empty() && TotalBytesReceived() > 0) { |
| 187 size_t index = AddOrMergeReceivedSliceIntoSortedArray( | 191 size_t index = AddOrMergeReceivedSliceIntoSortedArray( |
| 188 DownloadItem::ReceivedSlice(0, TotalBytesReceived()), received_slices_); | 192 DownloadItem::ReceivedSlice(0, TotalBytesReceived()), received_slices_); |
| 189 DCHECK_EQ(index, 0u); | 193 DCHECK_EQ(index, 0u); |
| 190 } | 194 } |
| 191 // If the file is initialized, start to write data, or wait until file opened. | 195 // If the file is initialized, start to write data, or wait until file opened. |
| 192 if (file_.in_progress()) | 196 if (file_.in_progress()) |
| 193 RegisterAndActivateStream(source_streams_[offset].get()); | 197 RegisterAndActivateStream(source_streams_[offset].get()); |
| 194 } | 198 } |
| 195 | 199 |
| 196 DownloadInterruptReason DownloadFileImpl::WriteDataToFile(int64_t offset, | 200 DownloadInterruptReason DownloadFileImpl::WriteDataToFile(int64_t offset, |
| 197 const char* data, | 201 const char* data, |
| 198 size_t data_len) { | 202 size_t data_len) { |
| 199 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 203 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 204 |
| 200 WillWriteToDisk(data_len); | 205 WillWriteToDisk(data_len); |
| 201 return file_.WriteDataToFile(offset, data, data_len); | 206 return file_.WriteDataToFile(offset, data, data_len); |
| 202 } | 207 } |
| 203 | 208 |
| 204 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, | 209 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, |
| 205 size_t bytes_available_to_write, | 210 size_t bytes_available_to_write, |
| 206 size_t* bytes_to_write) { | 211 size_t* bytes_to_write) { |
| 207 if (source_stream->length() == kNoBytesToWrite) { | 212 if (source_stream->length() == kNoBytesToWrite) { |
| 208 *bytes_to_write = 0; | 213 *bytes_to_write = 0; |
| 209 return true; | 214 return true; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 return base::TimeDelta::FromMilliseconds(kInitialRenameRetryDelayMs) * | 272 return base::TimeDelta::FromMilliseconds(kInitialRenameRetryDelayMs) * |
| 268 (1 << attempt_number); | 273 (1 << attempt_number); |
| 269 } | 274 } |
| 270 | 275 |
| 271 bool DownloadFileImpl::ShouldRetryFailedRename(DownloadInterruptReason reason) { | 276 bool DownloadFileImpl::ShouldRetryFailedRename(DownloadInterruptReason reason) { |
| 272 return reason == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR; | 277 return reason == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR; |
| 273 } | 278 } |
| 274 | 279 |
| 275 void DownloadFileImpl::RenameWithRetryInternal( | 280 void DownloadFileImpl::RenameWithRetryInternal( |
| 276 std::unique_ptr<RenameParameters> parameters) { | 281 std::unique_ptr<RenameParameters> parameters) { |
| 277 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 282 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 278 | 283 |
| 279 base::FilePath new_path = parameters->new_path; | 284 base::FilePath new_path = parameters->new_path; |
| 280 | 285 |
| 281 if ((parameters->option & UNIQUIFY) && new_path != file_.full_path()) { | 286 if ((parameters->option & UNIQUIFY) && new_path != file_.full_path()) { |
| 282 int uniquifier = | 287 int uniquifier = |
| 283 base::GetUniquePathNumber(new_path, base::FilePath::StringType()); | 288 base::GetUniquePathNumber(new_path, base::FilePath::StringType()); |
| 284 if (uniquifier > 0) | 289 if (uniquifier > 0) |
| 285 new_path = new_path.InsertBeforeExtensionASCII( | 290 new_path = new_path.InsertBeforeExtensionASCII( |
| 286 base::StringPrintf(" (%d)", uniquifier)); | 291 base::StringPrintf(" (%d)", uniquifier)); |
| 287 } | 292 } |
| 288 | 293 |
| 289 DownloadInterruptReason reason = file_.Rename(new_path); | 294 DownloadInterruptReason reason = file_.Rename(new_path); |
| 290 | 295 |
| 291 // Attempt to retry the rename if possible. If the rename failed and the | 296 // Attempt to retry the rename if possible. If the rename failed and the |
| 292 // subsequent open also failed, then in_progress() would be false. We don't | 297 // subsequent open also failed, then in_progress() would be false. We don't |
| 293 // try to retry renames if the in_progress() was false to begin with since we | 298 // try to retry renames if the in_progress() was false to begin with since we |
| 294 // have less assurance that the file at file_.full_path() was the one we were | 299 // have less assurance that the file at file_.full_path() was the one we were |
| 295 // working with. | 300 // working with. |
| 296 if (ShouldRetryFailedRename(reason) && file_.in_progress() && | 301 if (ShouldRetryFailedRename(reason) && file_.in_progress() && |
| 297 parameters->retries_left > 0) { | 302 parameters->retries_left > 0) { |
| 298 int attempt_number = kMaxRenameRetries - parameters->retries_left; | 303 int attempt_number = kMaxRenameRetries - parameters->retries_left; |
| 299 --parameters->retries_left; | 304 --parameters->retries_left; |
| 300 if (parameters->time_of_first_failure.is_null()) | 305 if (parameters->time_of_first_failure.is_null()) |
| 301 parameters->time_of_first_failure = base::TimeTicks::Now(); | 306 parameters->time_of_first_failure = base::TimeTicks::Now(); |
| 302 BrowserThread::PostDelayedTask( | 307 GetDownloadTaskRunner()->PostDelayedTask( |
| 303 BrowserThread::FILE, | |
| 304 FROM_HERE, | 308 FROM_HERE, |
| 305 base::Bind(&DownloadFileImpl::RenameWithRetryInternal, | 309 base::Bind(&DownloadFileImpl::RenameWithRetryInternal, |
| 306 weak_factory_.GetWeakPtr(), | 310 weak_factory_.GetWeakPtr(), |
| 307 base::Passed(std::move(parameters))), | 311 base::Passed(std::move(parameters))), |
| 308 GetRetryDelayForFailedRename(attempt_number)); | 312 GetRetryDelayForFailedRename(attempt_number)); |
| 309 return; | 313 return; |
| 310 } | 314 } |
| 311 | 315 |
| 312 if (!parameters->time_of_first_failure.is_null()) | 316 if (!parameters->time_of_first_failure.is_null()) |
| 313 RecordDownloadFileRenameResultAfterRetry( | 317 RecordDownloadFileRenameResultAfterRetry( |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 461 break; | 465 break; |
| 462 } | 466 } |
| 463 now = base::TimeTicks::Now(); | 467 now = base::TimeTicks::Now(); |
| 464 } while (state == ByteStreamReader::STREAM_HAS_DATA && | 468 } while (state == ByteStreamReader::STREAM_HAS_DATA && |
| 465 reason == DOWNLOAD_INTERRUPT_REASON_NONE && now - start <= delta && | 469 reason == DOWNLOAD_INTERRUPT_REASON_NONE && now - start <= delta && |
| 466 !should_terminate); | 470 !should_terminate); |
| 467 | 471 |
| 468 // If we're stopping to yield the thread, post a task so we come back. | 472 // If we're stopping to yield the thread, post a task so we come back. |
| 469 if (state == ByteStreamReader::STREAM_HAS_DATA && now - start > delta && | 473 if (state == ByteStreamReader::STREAM_HAS_DATA && now - start > delta && |
| 470 !should_terminate) { | 474 !should_terminate) { |
| 471 BrowserThread::PostTask( | 475 GetDownloadTaskRunner()->PostTask( |
| 472 BrowserThread::FILE, FROM_HERE, | 476 FROM_HERE, base::Bind(&DownloadFileImpl::StreamActive, |
| 473 base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr(), | 477 weak_factory_.GetWeakPtr(), source_stream)); |
| 474 source_stream)); | |
| 475 } | 478 } |
| 476 | 479 |
| 477 if (total_incoming_data_size) | 480 if (total_incoming_data_size) |
| 478 RecordFileThreadReceiveBuffers(num_buffers); | 481 RecordFileThreadReceiveBuffers(num_buffers); |
| 479 | 482 |
| 480 RecordContiguousWriteTime(now - start); | 483 RecordContiguousWriteTime(now - start); |
| 481 | 484 |
| 482 // Take care of communication with our observer. | 485 // Take care of communication with our observer. |
| 483 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { | 486 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { |
| 484 HandleStreamError(source_stream, reason); | 487 HandleStreamError(source_stream, reason); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 } | 522 } |
| 520 } | 523 } |
| 521 if (net_log_.IsCapturing()) { | 524 if (net_log_.IsCapturing()) { |
| 522 net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_STREAM_DRAINED, | 525 net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_STREAM_DRAINED, |
| 523 base::Bind(&FileStreamDrainedNetLogCallback, | 526 base::Bind(&FileStreamDrainedNetLogCallback, |
| 524 total_incoming_data_size, num_buffers)); | 527 total_incoming_data_size, num_buffers)); |
| 525 } | 528 } |
| 526 } | 529 } |
| 527 | 530 |
| 528 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { | 531 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { |
| 529 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 532 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 533 |
| 530 ByteStreamReader* stream_reader = source_stream->stream_reader(); | 534 ByteStreamReader* stream_reader = source_stream->stream_reader(); |
| 531 if (stream_reader) { | 535 if (stream_reader) { |
| 532 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, | 536 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, |
| 533 weak_factory_.GetWeakPtr(), | 537 weak_factory_.GetWeakPtr(), |
| 534 source_stream)); | 538 source_stream)); |
| 535 // Truncate |source_stream|'s length if necessary. | 539 // Truncate |source_stream|'s length if necessary. |
| 536 for (const auto& received_slice : received_slices_) { | 540 for (const auto& received_slice : received_slices_) { |
| 537 source_stream->TruncateLengthWithWrittenDataBlock( | 541 source_stream->TruncateLengthWithWrittenDataBlock( |
| 538 received_slice.offset, received_slice.received_bytes); | 542 received_slice.offset, received_slice.received_bytes); |
| 539 } | 543 } |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 609 if (slices_to_download.size() > 1) { | 613 if (slices_to_download.size() > 1) { |
| 610 // If there are 1 or more holes in the file, download is not finished. | 614 // If there are 1 or more holes in the file, download is not finished. |
| 611 // Some streams might not have been added to |source_streams_| yet. | 615 // Some streams might not have been added to |source_streams_| yet. |
| 612 return false; | 616 return false; |
| 613 } | 617 } |
| 614 return TotalBytesReceived() == potential_file_length_; | 618 return TotalBytesReceived() == potential_file_length_; |
| 615 } | 619 } |
| 616 | 620 |
| 617 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, | 621 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, |
| 618 DownloadInterruptReason reason) { | 622 DownloadInterruptReason reason) { |
| 619 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 623 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 624 |
| 620 source_stream->stream_reader()->RegisterCallback(base::Closure()); | 625 source_stream->stream_reader()->RegisterCallback(base::Closure()); |
| 621 source_stream->set_finished(true); | 626 source_stream->set_finished(true); |
| 622 num_active_streams_--; | 627 num_active_streams_--; |
| 623 | 628 |
| 624 bool can_recover_from_error = (source_stream->length() == kNoBytesToWrite); | 629 bool can_recover_from_error = (source_stream->length() == kNoBytesToWrite); |
| 625 | 630 |
| 626 if (IsSparseFile() && !can_recover_from_error) { | 631 if (IsSparseFile() && !can_recover_from_error) { |
| 627 // If a neighboring stream request is available, check if it can help | 632 // If a neighboring stream request is available, check if it can help |
| 628 // download all the data left by |source stream| or has already done so. We | 633 // download all the data left by |source stream| or has already done so. We |
| 629 // want to avoid the situation that a server always fail additional requests | 634 // want to avoid the situation that a server always fail additional requests |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 const base::FilePath& new_path, | 731 const base::FilePath& new_path, |
| 727 const RenameCompletionCallback& completion_callback) | 732 const RenameCompletionCallback& completion_callback) |
| 728 : option(option), | 733 : option(option), |
| 729 new_path(new_path), | 734 new_path(new_path), |
| 730 retries_left(kMaxRenameRetries), | 735 retries_left(kMaxRenameRetries), |
| 731 completion_callback(completion_callback) {} | 736 completion_callback(completion_callback) {} |
| 732 | 737 |
| 733 DownloadFileImpl::RenameParameters::~RenameParameters() {} | 738 DownloadFileImpl::RenameParameters::~RenameParameters() {} |
| 734 | 739 |
| 735 } // namespace content | 740 } // namespace content |
| OLD | NEW |