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 |