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