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_item_impl.h" | 5 #include "content/browser/download/download_item_impl.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
12 #include "base/format_macros.h" | 12 #include "base/format_macros.h" |
13 #include "base/i18n/case_conversion.h" | 13 #include "base/i18n/case_conversion.h" |
14 #include "base/i18n/string_search.h" | 14 #include "base/i18n/string_search.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
18 #include "base/stringprintf.h" | 18 #include "base/stringprintf.h" |
19 #include "base/utf_string_conversions.h" | 19 #include "base/utf_string_conversions.h" |
20 #include "content/browser/download/download_create_info.h" | 20 #include "content/browser/download/download_create_info.h" |
21 #include "content/browser/download/download_file.h" | 21 #include "content/browser/download/download_file.h" |
22 #include "content/browser/download/download_file_manager.h" | |
23 #include "content/browser/download/download_interrupt_reasons_impl.h" | 22 #include "content/browser/download/download_interrupt_reasons_impl.h" |
24 #include "content/browser/download/download_item_impl_delegate.h" | 23 #include "content/browser/download/download_item_impl_delegate.h" |
25 #include "content/browser/download/download_request_handle.h" | 24 #include "content/browser/download/download_request_handle.h" |
26 #include "content/browser/download/download_stats.h" | 25 #include "content/browser/download/download_stats.h" |
27 #include "content/browser/web_contents/web_contents_impl.h" | 26 #include "content/browser/web_contents/web_contents_impl.h" |
28 #include "content/public/browser/browser_thread.h" | 27 #include "content/public/browser/browser_thread.h" |
29 #include "content/public/browser/content_browser_client.h" | 28 #include "content/public/browser/content_browser_client.h" |
30 #include "content/public/browser/download_persistent_store_info.h" | 29 #include "content/public/browser/download_persistent_store_info.h" |
31 #include "net/base/net_util.h" | 30 #include "net/base/net_util.h" |
32 | 31 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 return NULL; | 111 return NULL; |
113 } | 112 } |
114 virtual void PauseRequest() const OVERRIDE {} | 113 virtual void PauseRequest() const OVERRIDE {} |
115 virtual void ResumeRequest() const OVERRIDE {} | 114 virtual void ResumeRequest() const OVERRIDE {} |
116 virtual void CancelRequest() const OVERRIDE {} | 115 virtual void CancelRequest() const OVERRIDE {} |
117 virtual std::string DebugString() const OVERRIDE { | 116 virtual std::string DebugString() const OVERRIDE { |
118 return "Null DownloadRequestHandle"; | 117 return "Null DownloadRequestHandle"; |
119 } | 118 } |
120 }; | 119 }; |
121 | 120 |
| 121 // Wrapper around DownloadFile::Detach and DownloadFile::Cancel that |
| 122 // takes ownership of the DownloadFile and hence implicitly destroys it |
| 123 // at the end of the function. |
| 124 static void DownloadFileDetach(scoped_ptr<DownloadFile> download_file) { |
| 125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 126 download_file->Detach(); |
| 127 } |
| 128 |
| 129 static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) { |
| 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 131 download_file->Cancel(); |
| 132 } |
| 133 |
122 } // namespace | 134 } // namespace |
123 | 135 |
124 namespace content { | 136 namespace content { |
125 | 137 |
126 // Our download table ID starts at 1, so we use 0 to represent a download that | 138 // Our download table ID starts at 1, so we use 0 to represent a download that |
127 // has started, but has not yet had its data persisted in the table. We use fake | 139 // has started, but has not yet had its data persisted in the table. We use fake |
128 // database handles in incognito mode starting at -1 and progressively getting | 140 // database handles in incognito mode starting at -1 and progressively getting |
129 // more negative. | 141 // more negative. |
130 // static | 142 // static |
131 const int DownloadItem::kUninitializedHandle = 0; | 143 const int DownloadItem::kUninitializedHandle = 0; |
132 | 144 |
133 const char DownloadItem::kEmptyFileHash[] = ""; | 145 const char DownloadItem::kEmptyFileHash[] = ""; |
134 | 146 |
135 } | 147 } |
136 | 148 |
137 // Our download table ID starts at 1, so we use 0 to represent a download that | 149 // Our download table ID starts at 1, so we use 0 to represent a download that |
138 // has started, but has not yet had its data persisted in the table. We use fake | 150 // has started, but has not yet had its data persisted in the table. We use fake |
139 // database handles in incognito mode starting at -1 and progressively getting | 151 // database handles in incognito mode starting at -1 and progressively getting |
140 // more negative. | 152 // more negative. |
141 | 153 |
142 // Constructor for reading from the history service. | 154 // Constructor for reading from the history service. |
143 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, | 155 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, |
144 DownloadId download_id, | 156 DownloadId download_id, |
145 const DownloadPersistentStoreInfo& info, | 157 const DownloadPersistentStoreInfo& info, |
146 const net::BoundNetLog& bound_net_log) | 158 const net::BoundNetLog& bound_net_log) |
147 : download_id_(download_id), | 159 : is_save_package_download_(false), |
| 160 download_id_(download_id), |
148 current_path_(info.path), | 161 current_path_(info.path), |
149 target_path_(info.path), | 162 target_path_(info.path), |
150 target_disposition_(TARGET_DISPOSITION_OVERWRITE), | 163 target_disposition_(TARGET_DISPOSITION_OVERWRITE), |
151 url_chain_(1, info.url), | 164 url_chain_(1, info.url), |
152 referrer_url_(info.referrer_url), | 165 referrer_url_(info.referrer_url), |
153 transition_type_(content::PAGE_TRANSITION_LINK), | 166 transition_type_(content::PAGE_TRANSITION_LINK), |
154 has_user_gesture_(false), | 167 has_user_gesture_(false), |
155 total_bytes_(info.total_bytes), | 168 total_bytes_(info.total_bytes), |
156 received_bytes_(info.received_bytes), | 169 received_bytes_(info.received_bytes), |
157 bytes_per_sec_(0), | 170 bytes_per_sec_(0), |
(...skipping 26 matching lines...) Expand all Loading... |
184 Init(false /* not actively downloading */, | 197 Init(false /* not actively downloading */, |
185 download_net_logs::SRC_HISTORY_IMPORT); | 198 download_net_logs::SRC_HISTORY_IMPORT); |
186 } | 199 } |
187 | 200 |
188 // Constructing for a regular download: | 201 // Constructing for a regular download: |
189 DownloadItemImpl::DownloadItemImpl( | 202 DownloadItemImpl::DownloadItemImpl( |
190 DownloadItemImplDelegate* delegate, | 203 DownloadItemImplDelegate* delegate, |
191 const DownloadCreateInfo& info, | 204 const DownloadCreateInfo& info, |
192 scoped_ptr<DownloadRequestHandleInterface> request_handle, | 205 scoped_ptr<DownloadRequestHandleInterface> request_handle, |
193 const net::BoundNetLog& bound_net_log) | 206 const net::BoundNetLog& bound_net_log) |
194 : request_handle_(request_handle.Pass()), | 207 : is_save_package_download_(false), |
| 208 request_handle_(request_handle.Pass()), |
195 download_id_(info.download_id), | 209 download_id_(info.download_id), |
196 target_disposition_( | 210 target_disposition_( |
197 (info.prompt_user_for_save_location) ? | 211 (info.prompt_user_for_save_location) ? |
198 TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE), | 212 TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE), |
199 url_chain_(info.url_chain), | 213 url_chain_(info.url_chain), |
200 referrer_url_(info.referrer_url), | 214 referrer_url_(info.referrer_url), |
201 suggested_filename_(UTF16ToUTF8(info.save_info.suggested_name)), | 215 suggested_filename_(UTF16ToUTF8(info.save_info.suggested_name)), |
202 forced_file_path_(info.save_info.file_path), | 216 forced_file_path_(info.save_info.file_path), |
203 transition_type_(info.transition_type), | 217 transition_type_(info.transition_type), |
204 has_user_gesture_(info.has_user_gesture), | 218 has_user_gesture_(info.has_user_gesture), |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 bound_net_log_.source().ToEventParametersCallback()); | 258 bound_net_log_.source().ToEventParametersCallback()); |
245 } | 259 } |
246 | 260 |
247 // Constructing for the "Save Page As..." feature: | 261 // Constructing for the "Save Page As..." feature: |
248 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, | 262 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, |
249 const FilePath& path, | 263 const FilePath& path, |
250 const GURL& url, | 264 const GURL& url, |
251 DownloadId download_id, | 265 DownloadId download_id, |
252 const std::string& mime_type, | 266 const std::string& mime_type, |
253 const net::BoundNetLog& bound_net_log) | 267 const net::BoundNetLog& bound_net_log) |
254 : request_handle_(new NullDownloadRequestHandle()), | 268 : is_save_package_download_(true), |
| 269 request_handle_(new NullDownloadRequestHandle()), |
255 download_id_(download_id), | 270 download_id_(download_id), |
256 current_path_(path), | 271 current_path_(path), |
257 target_path_(path), | 272 target_path_(path), |
258 target_disposition_(TARGET_DISPOSITION_OVERWRITE), | 273 target_disposition_(TARGET_DISPOSITION_OVERWRITE), |
259 url_chain_(1, url), | 274 url_chain_(1, url), |
260 referrer_url_(GURL()), | 275 referrer_url_(GURL()), |
261 transition_type_(content::PAGE_TRANSITION_LINK), | 276 transition_type_(content::PAGE_TRANSITION_LINK), |
262 has_user_gesture_(false), | 277 has_user_gesture_(false), |
263 mime_type_(mime_type), | 278 mime_type_(mime_type), |
264 original_mime_type_(mime_type), | 279 original_mime_type_(mime_type), |
(...skipping 20 matching lines...) Expand all Loading... |
285 delegate_delayed_complete_(false), | 300 delegate_delayed_complete_(false), |
286 bound_net_log_(bound_net_log), | 301 bound_net_log_(bound_net_log), |
287 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | 302 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
288 delegate_->Attach(); | 303 delegate_->Attach(); |
289 Init(true /* actively downloading */, | 304 Init(true /* actively downloading */, |
290 download_net_logs::SRC_SAVE_PAGE_AS); | 305 download_net_logs::SRC_SAVE_PAGE_AS); |
291 } | 306 } |
292 | 307 |
293 DownloadItemImpl::~DownloadItemImpl() { | 308 DownloadItemImpl::~DownloadItemImpl() { |
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 310 |
| 311 // Should always have been nuked before now, at worst in |
| 312 // DownloadManager shutdown. |
| 313 DCHECK(!download_file_.get()); |
| 314 |
295 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this)); | 315 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this)); |
296 delegate_->AssertStateConsistent(this); | 316 delegate_->AssertStateConsistent(this); |
297 delegate_->Detach(); | 317 delegate_->Detach(); |
298 } | 318 } |
299 | 319 |
| 320 base::WeakPtr<content::DownloadDestinationObserver> |
| 321 DownloadItemImpl::DestinationObserverAsWeakPtr() { |
| 322 // Return does private downcast. |
| 323 return weak_ptr_factory_.GetWeakPtr(); |
| 324 } |
| 325 |
300 void DownloadItemImpl::AddObserver(Observer* observer) { | 326 void DownloadItemImpl::AddObserver(Observer* observer) { |
301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
302 | 328 |
303 observers_.AddObserver(observer); | 329 observers_.AddObserver(observer); |
304 } | 330 } |
305 | 331 |
306 void DownloadItemImpl::RemoveObserver(Observer* observer) { | 332 void DownloadItemImpl::RemoveObserver(Observer* observer) { |
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
308 | 334 |
309 observers_.RemoveObserver(observer); | 335 observers_.RemoveObserver(observer); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 bound_net_log_.AddEvent( | 404 bound_net_log_.AddEvent( |
379 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED, | 405 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED, |
380 base::Bind(&download_net_logs::ItemCheckedCallback, | 406 base::Bind(&download_net_logs::ItemCheckedCallback, |
381 GetDangerType(), GetSafetyState())); | 407 GetDangerType(), GetSafetyState())); |
382 | 408 |
383 UpdateObservers(); | 409 UpdateObservers(); |
384 | 410 |
385 delegate_->MaybeCompleteDownload(this); | 411 delegate_->MaybeCompleteDownload(this); |
386 } | 412 } |
387 | 413 |
388 void DownloadItemImpl::ProgressComplete(int64 bytes_so_far, | |
389 const std::string& final_hash) { | |
390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
391 | |
392 hash_ = final_hash; | |
393 hash_state_ = ""; | |
394 | |
395 received_bytes_ = bytes_so_far; | |
396 | |
397 // If we've received more data than we were expecting (bad server info?), | |
398 // revert to 'unknown size mode'. | |
399 if (received_bytes_ > total_bytes_) | |
400 total_bytes_ = 0; | |
401 } | |
402 | |
403 // Updates from the download thread may have been posted while this download | 414 // Updates from the download thread may have been posted while this download |
404 // was being cancelled in the UI thread, so we'll accept them unless we're | 415 // was being cancelled in the UI thread, so we'll accept them unless we're |
405 // complete. | 416 // complete. |
406 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, | 417 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, |
407 int64 bytes_per_sec, | 418 int64 bytes_per_sec, |
408 const std::string& hash_state) { | 419 const std::string& hash_state) { |
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
410 | 421 |
411 if (!IsInProgress()) { | 422 if (!IsInProgress()) { |
412 // Ignore if we're no longer in-progress. This can happen if we race a | 423 // Ignore if we're no longer in-progress. This can happen if we race a |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); | 460 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); |
450 if (!IsPartialDownload()) { | 461 if (!IsPartialDownload()) { |
451 // Small downloads might be complete before this method has | 462 // Small downloads might be complete before this method has |
452 // a chance to run. | 463 // a chance to run. |
453 return; | 464 return; |
454 } | 465 } |
455 | 466 |
456 download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT); | 467 download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT); |
457 | 468 |
458 TransitionTo(CANCELLED); | 469 TransitionTo(CANCELLED); |
| 470 |
| 471 // Cancel and remove the download file. |
| 472 // TODO(rdsmith/benjhayden): Remove condition as part of |
| 473 // SavePackage integration. |
| 474 if (!is_save_package_download_) { |
| 475 CHECK(download_file_.get()); |
| 476 BrowserThread::PostTask( |
| 477 BrowserThread::FILE, FROM_HERE, |
| 478 // Will be deleted at end of task execution. |
| 479 base::Bind(&DownloadFileCancel, base::Passed(download_file_.Pass()))); |
| 480 } |
| 481 |
| 482 // Cancel the originating URL request. |
| 483 request_handle_->CancelRequest(); |
| 484 |
459 if (user_cancel) | 485 if (user_cancel) |
460 delegate_->DownloadStopped(this); | 486 delegate_->DownloadStopped(this); |
461 } | 487 } |
462 | 488 |
| 489 // We're starting the download. |
| 490 void DownloadItemImpl::Start(scoped_ptr<content::DownloadFile> download_file) { |
| 491 DCHECK(!download_file_.get()); |
| 492 download_file_ = download_file.Pass(); |
| 493 |
| 494 BrowserThread::PostTask( |
| 495 BrowserThread::FILE, FROM_HERE, |
| 496 base::Bind(&DownloadFile::Initialize, |
| 497 // Safe because we control download file lifetime. |
| 498 base::Unretained(download_file_.get()), |
| 499 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, |
| 500 weak_ptr_factory_.GetWeakPtr()))); |
| 501 } |
| 502 |
463 // An error occurred somewhere. | 503 // An error occurred somewhere. |
464 void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) { | 504 void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) { |
465 // Somewhat counter-intuitively, it is possible for us to receive an | 505 // Somewhat counter-intuitively, it is possible for us to receive an |
466 // interrupt after we've already been interrupted. The generation of | 506 // interrupt after we've already been interrupted. The generation of |
467 // interrupts from the file thread Renames and the generation of | 507 // interrupts from the file thread Renames and the generation of |
468 // interrupts from disk writes go through two different mechanisms (driven | 508 // interrupts from disk writes go through two different mechanisms (driven |
469 // by rename requests from UI thread and by write requests from IO thread, | 509 // by rename requests from UI thread and by write requests from IO thread, |
470 // respectively), and since we choose not to keep state on the File thread, | 510 // respectively), and since we choose not to keep state on the File thread, |
471 // this is the place where the races collide. It's also possible for | 511 // this is the place where the races collide. It's also possible for |
472 // interrupts to race with cancels. | 512 // interrupts to race with cancels. |
473 | 513 |
474 // Whatever happens, the first one to hit the UI thread wins. | 514 // Whatever happens, the first one to hit the UI thread wins. |
475 if (!IsInProgress()) | 515 if (!IsInProgress()) |
476 return; | 516 return; |
477 | 517 |
478 last_reason_ = reason; | 518 last_reason_ = reason; |
479 TransitionTo(INTERRUPTED); | 519 TransitionTo(INTERRUPTED); |
| 520 |
| 521 // Cancel and remove the download file. |
| 522 // TODO(rdsmith/benjhayden): Remove condition as part of |
| 523 // SavePackage integration. |
| 524 if (!is_save_package_download_) { |
| 525 CHECK(download_file_.get()); |
| 526 BrowserThread::PostTask( |
| 527 BrowserThread::FILE, FROM_HERE, |
| 528 // Will be deleted at end of task execution. |
| 529 base::Bind(&DownloadFileCancel, base::Passed(download_file_.Pass()))); |
| 530 } |
| 531 |
| 532 // Cancel the originating URL request. |
| 533 request_handle_->CancelRequest(); |
| 534 |
480 download_stats::RecordDownloadInterrupted( | 535 download_stats::RecordDownloadInterrupted( |
481 reason, received_bytes_, total_bytes_); | 536 reason, received_bytes_, total_bytes_); |
482 delegate_->DownloadStopped(this); | 537 delegate_->DownloadStopped(this); |
483 } | 538 } |
484 | 539 |
485 void DownloadItemImpl::MarkAsComplete() { | 540 void DownloadItemImpl::MarkAsComplete() { |
486 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 541 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
487 | 542 |
488 DCHECK(all_data_saved_); | 543 DCHECK(all_data_saved_); |
489 end_time_ = base::Time::Now(); | 544 end_time_ = base::Time::Now(); |
490 TransitionTo(COMPLETE); | 545 TransitionTo(COMPLETE); |
491 } | 546 } |
492 | 547 |
493 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { | 548 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { |
494 auto_opened_ = auto_opened; | 549 auto_opened_ = auto_opened; |
495 Completed(); | 550 Completed(); |
496 } | 551 } |
497 | 552 |
498 void DownloadItemImpl::OnAllDataSaved( | 553 void DownloadItemImpl::OnAllDataSaved( |
499 int64 size, const std::string& final_hash) { | 554 const std::string& final_hash) { |
500 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 555 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
501 | 556 |
| 557 DCHECK_EQ(IN_PROGRESS, state_); |
502 DCHECK(!all_data_saved_); | 558 DCHECK(!all_data_saved_); |
503 all_data_saved_ = true; | 559 all_data_saved_ = true; |
504 ProgressComplete(size, final_hash); | 560 |
| 561 // Store final hash and null out intermediate serialized hash state. |
| 562 hash_ = final_hash; |
| 563 hash_state_ = ""; |
| 564 |
505 UpdateObservers(); | 565 UpdateObservers(); |
506 } | 566 } |
507 | 567 |
508 void DownloadItemImpl::OnDownloadedFileRemoved() { | 568 void DownloadItemImpl::OnDownloadedFileRemoved() { |
509 file_externally_removed_ = true; | 569 file_externally_removed_ = true; |
510 UpdateObservers(); | 570 UpdateObservers(); |
511 } | 571 } |
512 | 572 |
513 void DownloadItemImpl::MaybeCompleteDownload() { | 573 void DownloadItemImpl::MaybeCompleteDownload() { |
514 // TODO(rdsmith): Move logic for this function here. | 574 // TODO(rdsmith): Move logic for this function here. |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
659 | 719 |
660 int64 speed = CurrentSpeed(); | 720 int64 speed = CurrentSpeed(); |
661 if (speed == 0) | 721 if (speed == 0) |
662 return false; | 722 return false; |
663 | 723 |
664 *remaining = base::TimeDelta::FromSeconds( | 724 *remaining = base::TimeDelta::FromSeconds( |
665 (total_bytes_ - received_bytes_) / speed); | 725 (total_bytes_ - received_bytes_) / speed); |
666 return true; | 726 return true; |
667 } | 727 } |
668 | 728 |
| 729 bool DownloadItemImpl::IsSavePackageDownload() const { |
| 730 return is_save_package_download_; |
| 731 } |
| 732 |
669 int64 DownloadItemImpl::CurrentSpeed() const { | 733 int64 DownloadItemImpl::CurrentSpeed() const { |
670 if (is_paused_) | 734 if (is_paused_) |
671 return 0; | 735 return 0; |
672 return bytes_per_sec_; | 736 return bytes_per_sec_; |
673 } | 737 } |
674 | 738 |
675 int DownloadItemImpl::PercentComplete() const { | 739 int DownloadItemImpl::PercentComplete() const { |
676 // If the delegate is delaying completion of the download, then we have no | 740 // If the delegate is delaying completion of the download, then we have no |
677 // idea how long it will take. | 741 // idea how long it will take. |
678 if (delegate_delayed_complete_ || total_bytes_ <= 0) | 742 if (delegate_delayed_complete_ || total_bytes_ <= 0) |
(...skipping 10 matching lines...) Expand all Loading... |
689 request_handle_->ResumeRequest(); | 753 request_handle_->ResumeRequest(); |
690 else | 754 else |
691 request_handle_->PauseRequest(); | 755 request_handle_->PauseRequest(); |
692 is_paused_ = !is_paused_; | 756 is_paused_ = !is_paused_; |
693 UpdateObservers(); | 757 UpdateObservers(); |
694 } | 758 } |
695 | 759 |
696 void DownloadItemImpl::OnDownloadCompleting() { | 760 void DownloadItemImpl::OnDownloadCompleting() { |
697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 761 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
698 | 762 |
| 763 if (!IsInProgress()) |
| 764 return; |
| 765 |
699 VLOG(20) << __FUNCTION__ << "()" | 766 VLOG(20) << __FUNCTION__ << "()" |
700 << " needs rename = " << NeedsRename() | 767 << " needs rename = " << NeedsRename() |
701 << " " << DebugString(true); | 768 << " " << DebugString(true); |
702 DCHECK(!GetTargetName().empty()); | 769 DCHECK(!GetTargetName().empty()); |
703 DCHECK_NE(DANGEROUS, GetSafetyState()); | 770 DCHECK_NE(DANGEROUS, GetSafetyState()); |
704 | 771 |
| 772 // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration. |
| 773 if (is_save_package_download_) { |
| 774 // Avoid doing anything on the file thread; there's nothing we control |
| 775 // there. |
| 776 OnDownloadFileReleased(); |
| 777 return; |
| 778 } |
| 779 |
| 780 CHECK(download_file_.get()); |
705 if (NeedsRename()) { | 781 if (NeedsRename()) { |
706 DownloadFileManager::RenameCompletionCallback callback = | 782 content::DownloadFile::RenameCompletionCallback callback = |
707 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, | 783 base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName, |
708 weak_ptr_factory_.GetWeakPtr()); | 784 weak_ptr_factory_.GetWeakPtr()); |
709 BrowserThread::PostTask( | 785 BrowserThread::PostTask( |
710 BrowserThread::FILE, FROM_HERE, | 786 BrowserThread::FILE, FROM_HERE, |
711 base::Bind(&DownloadFileManager::RenameDownloadFile, | 787 base::Bind(&DownloadFile::Rename, |
712 delegate_->GetDownloadFileManager(), GetGlobalId(), | 788 base::Unretained(download_file_.get()), |
713 GetTargetFilePath(), true, callback)); | 789 GetTargetFilePath(), true, callback)); |
714 } else { | 790 } else { |
715 // Complete the download and release the DownloadFile. | 791 // Complete the download and release the DownloadFile. |
716 BrowserThread::PostTask( | 792 BrowserThread::PostTaskAndReply( |
717 BrowserThread::FILE, FROM_HERE, | 793 BrowserThread::FILE, FROM_HERE, |
718 base::Bind(&DownloadFileManager::CompleteDownload, | 794 base::Bind(&DownloadFileDetach, base::Passed(download_file_.Pass())), |
719 delegate_->GetDownloadFileManager(), GetGlobalId(), | 795 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, |
720 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, | 796 weak_ptr_factory_.GetWeakPtr())); |
721 weak_ptr_factory_.GetWeakPtr()))); | |
722 } | 797 } |
723 } | 798 } |
724 | 799 |
725 void DownloadItemImpl::OnDownloadRenamedToFinalName( | 800 void DownloadItemImpl::OnDownloadRenamedToFinalName( |
726 content::DownloadInterruptReason reason, | 801 content::DownloadInterruptReason reason, |
727 const FilePath& full_path) { | 802 const FilePath& full_path) { |
728 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 803 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
729 | 804 |
| 805 if (!IsInProgress()) |
| 806 return; |
| 807 |
730 VLOG(20) << __FUNCTION__ << "()" | 808 VLOG(20) << __FUNCTION__ << "()" |
731 << " full_path = \"" << full_path.value() << "\"" | 809 << " full_path = \"" << full_path.value() << "\"" |
732 << " needed rename = " << NeedsRename() | 810 << " needed rename = " << NeedsRename() |
733 << " " << DebugString(false); | 811 << " " << DebugString(false); |
734 DCHECK(NeedsRename()); | 812 DCHECK(NeedsRename()); |
735 | 813 |
736 if (content::DOWNLOAD_INTERRUPT_REASON_NONE != reason) { | 814 if (content::DOWNLOAD_INTERRUPT_REASON_NONE != reason) { |
737 Interrupt(reason); | 815 Interrupt(reason); |
738 return; | 816 return; |
739 } | 817 } |
740 | 818 |
741 // full_path is now the current and target file path. | 819 // full_path is now the current and target file path. |
742 DCHECK(!full_path.empty()); | 820 DCHECK(!full_path.empty()); |
743 target_path_ = full_path; | 821 target_path_ = full_path; |
744 SetFullPath(full_path); | 822 SetFullPath(full_path); |
745 delegate_->DownloadRenamedToFinalName(this); | 823 delegate_->DownloadRenamedToFinalName(this); |
746 | 824 |
747 // Complete the download and release the DownloadFile. | 825 // Complete the download and release the DownloadFile. |
748 BrowserThread::PostTask( | 826 // TODO(rdsmith): Unify this path with the !NeedsRename() path in |
| 827 // OnDownloadCompleting above. This can happen easily after history |
| 828 // is made into an observer and the path accessors are cleaned up; |
| 829 // that should allow OnDownloadCompleting to simply call |
| 830 // OnDownloadRenamedToFinalName directly. |
| 831 DCHECK(!is_save_package_download_); |
| 832 CHECK(download_file_.get()); |
| 833 BrowserThread::PostTaskAndReply( |
749 BrowserThread::FILE, FROM_HERE, | 834 BrowserThread::FILE, FROM_HERE, |
750 base::Bind(&DownloadFileManager::CompleteDownload, | 835 base::Bind(&DownloadFileDetach, base::Passed(download_file_.Pass())), |
751 delegate_->GetDownloadFileManager(), GetGlobalId(), | 836 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, |
752 base::Bind(&DownloadItemImpl::OnDownloadFileReleased, | 837 weak_ptr_factory_.GetWeakPtr())); |
753 weak_ptr_factory_.GetWeakPtr()))); | 838 } |
| 839 |
| 840 void DownloadItemImpl::OnDownloadFileInitialized( |
| 841 content::DownloadInterruptReason result) { |
| 842 if (result != content::DOWNLOAD_INTERRUPT_REASON_NONE) { |
| 843 Interrupt(result); |
| 844 // TODO(rdsmith): It makes no sense to continue along the |
| 845 // regular download path after we've gotten an error. But it's |
| 846 // the way the code has historically worked, and this allows us |
| 847 // to get the download persisted and observers of the download manager |
| 848 // notified, so tests work. When we execute all side effects of cancel |
| 849 // (including queue removal) immedately rather than waiting for |
| 850 // persistence we should replace this comment with a "return;". |
| 851 } |
| 852 |
| 853 delegate_->DelegateStart(this); |
754 } | 854 } |
755 | 855 |
756 void DownloadItemImpl::OnDownloadFileReleased() { | 856 void DownloadItemImpl::OnDownloadFileReleased() { |
757 if (delegate_->ShouldOpenDownload(this)) | 857 if (delegate_->ShouldOpenDownload(this)) |
758 Completed(); | 858 Completed(); |
759 else | 859 else |
760 delegate_delayed_complete_ = true; | 860 delegate_delayed_complete_ = true; |
761 } | 861 } |
762 | 862 |
763 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( | 863 void DownloadItemImpl::OnDownloadRenamedToIntermediateName( |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
874 target_path_ = target_path; | 974 target_path_ = target_path; |
875 target_disposition_ = disposition; | 975 target_disposition_ = disposition; |
876 SetDangerType(danger_type); | 976 SetDangerType(danger_type); |
877 // TODO(asanka): SetDangerType() doesn't need to send a notification here. | 977 // TODO(asanka): SetDangerType() doesn't need to send a notification here. |
878 | 978 |
879 // We want the intermediate and target paths to refer to the same directory so | 979 // We want the intermediate and target paths to refer to the same directory so |
880 // that they are both on the same device and subject to same | 980 // that they are both on the same device and subject to same |
881 // space/permission/availability constraints. | 981 // space/permission/availability constraints. |
882 DCHECK(intermediate_path.DirName() == target_path.DirName()); | 982 DCHECK(intermediate_path.DirName() == target_path.DirName()); |
883 | 983 |
| 984 if (!IsInProgress()) { |
| 985 // If we've been cancelled or interrupted while the target was being |
| 986 // determined, continue the cascade with a null name. |
| 987 // The error doesn't matter as the cause of download stoppaged |
| 988 // will already have been recorded. |
| 989 OnDownloadRenamedToIntermediateName( |
| 990 content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, FilePath()); |
| 991 return; |
| 992 } |
| 993 |
884 // Rename to intermediate name. | 994 // Rename to intermediate name. |
885 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a | 995 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a |
886 // spurious rename when we can just rename to the final | 996 // spurious rename when we can just rename to the final |
887 // filename. Unnecessary renames may cause bugs like | 997 // filename. Unnecessary renames may cause bugs like |
888 // http://crbug.com/74187. | 998 // http://crbug.com/74187. |
889 DownloadFileManager::RenameCompletionCallback callback = | 999 DCHECK(!is_save_package_download_); |
| 1000 CHECK(download_file_.get()); |
| 1001 DownloadFile::RenameCompletionCallback callback = |
890 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, | 1002 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, |
891 weak_ptr_factory_.GetWeakPtr()); | 1003 weak_ptr_factory_.GetWeakPtr()); |
892 BrowserThread::PostTask( | 1004 BrowserThread::PostTask( |
893 BrowserThread::FILE, FROM_HERE, | 1005 BrowserThread::FILE, FROM_HERE, |
894 base::Bind(&DownloadFileManager::RenameDownloadFile, | 1006 base::Bind(&DownloadFile::Rename, |
895 delegate_->GetDownloadFileManager(), GetGlobalId(), | 1007 // Safe because we control download file lifetime. |
| 1008 base::Unretained(download_file_.get()), |
896 intermediate_path, false, callback)); | 1009 intermediate_path, false, callback)); |
897 } | 1010 } |
898 | 1011 |
899 void DownloadItemImpl::OnContentCheckCompleted( | 1012 void DownloadItemImpl::OnContentCheckCompleted( |
900 content::DownloadDangerType danger_type) { | 1013 content::DownloadDangerType danger_type) { |
901 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1014 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
902 DCHECK(AllDataSaved()); | 1015 DCHECK(AllDataSaved()); |
903 SetDangerType(danger_type); | 1016 SetDangerType(danger_type); |
904 UpdateObservers(); | 1017 UpdateObservers(); |
905 } | 1018 } |
(...skipping 10 matching lines...) Expand all Loading... |
916 | 1029 |
917 void DownloadItemImpl::SetDisplayName(const FilePath& name) { | 1030 void DownloadItemImpl::SetDisplayName(const FilePath& name) { |
918 display_name_ = name; | 1031 display_name_ = name; |
919 } | 1032 } |
920 | 1033 |
921 FilePath DownloadItemImpl::GetUserVerifiedFilePath() const { | 1034 FilePath DownloadItemImpl::GetUserVerifiedFilePath() const { |
922 return (safety_state_ == DownloadItem::SAFE) ? | 1035 return (safety_state_ == DownloadItem::SAFE) ? |
923 GetTargetFilePath() : GetFullPath(); | 1036 GetTargetFilePath() : GetFullPath(); |
924 } | 1037 } |
925 | 1038 |
926 void DownloadItemImpl::OffThreadCancel() { | 1039 void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far, |
| 1040 int64 bytes_per_sec, |
| 1041 const std::string& hash_state) { |
927 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1042 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
928 request_handle_->CancelRequest(); | |
929 | 1043 |
930 BrowserThread::PostTask( | 1044 if (!IsInProgress()) { |
931 BrowserThread::FILE, FROM_HERE, | 1045 // Ignore if we're no longer in-progress. This can happen if we race a |
932 base::Bind(&DownloadFileManager::CancelDownload, | 1046 // Cancel on the UI thread with an update on the FILE thread. |
933 delegate_->GetDownloadFileManager(), download_id_)); | 1047 // |
| 1048 // TODO(rdsmith): Arguably we should let this go through, as this means |
| 1049 // the download really did get further than we know before it was |
| 1050 // cancelled. But the gain isn't very large, and the code is more |
| 1051 // fragile if it has to support in progress updates in a non-in-progress |
| 1052 // state. This issue should be readdressed when we revamp performance |
| 1053 // reporting. |
| 1054 return; |
| 1055 } |
| 1056 bytes_per_sec_ = bytes_per_sec; |
| 1057 hash_state_ = hash_state; |
| 1058 received_bytes_ = bytes_so_far; |
| 1059 |
| 1060 // If we've received more data than we were expecting (bad server info?), |
| 1061 // revert to 'unknown size mode'. |
| 1062 if (received_bytes_ > total_bytes_) |
| 1063 total_bytes_ = 0; |
| 1064 |
| 1065 if (bound_net_log_.IsLoggingAllEvents()) { |
| 1066 bound_net_log_.AddEvent( |
| 1067 net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED, |
| 1068 net::NetLog::Int64Callback("bytes_so_far", received_bytes_)); |
| 1069 } |
| 1070 |
| 1071 UpdateObservers(); |
| 1072 } |
| 1073 |
| 1074 void DownloadItemImpl::DestinationError( |
| 1075 content::DownloadInterruptReason reason) { |
| 1076 // The DestinationError and Interrupt routines are being kept separate |
| 1077 // to allow for a future merging of the Cancel and Interrupt routines.. |
| 1078 Interrupt(reason); |
| 1079 } |
| 1080 |
| 1081 void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) { |
| 1082 if (!IsInProgress()) |
| 1083 return; |
| 1084 OnAllDataSaved(final_hash); |
| 1085 delegate_->MaybeCompleteDownload(this); |
934 } | 1086 } |
935 | 1087 |
936 void DownloadItemImpl::Init(bool active, | 1088 void DownloadItemImpl::Init(bool active, |
937 download_net_logs::DownloadType download_type) { | 1089 download_net_logs::DownloadType download_type) { |
938 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1090 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
939 | 1091 |
940 if (active) | 1092 if (active) |
941 download_stats::RecordDownloadCount(download_stats::START_COUNT); | 1093 download_stats::RecordDownloadCount(download_stats::START_COUNT); |
942 | 1094 |
943 if (target_path_.empty()) | 1095 if (target_path_.empty()) |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1033 " db_handle = %" PRId64 | 1185 " db_handle = %" PRId64 |
1034 " total = %" PRId64 | 1186 " total = %" PRId64 |
1035 " received = %" PRId64 | 1187 " received = %" PRId64 |
1036 " reason = %s" | 1188 " reason = %s" |
1037 " paused = %c" | 1189 " paused = %c" |
1038 " safety = %s" | 1190 " safety = %s" |
1039 " last_modified = '%s'" | 1191 " last_modified = '%s'" |
1040 " etag = '%s'" | 1192 " etag = '%s'" |
1041 " url_chain = \n\t\"%s\"\n\t" | 1193 " url_chain = \n\t\"%s\"\n\t" |
1042 " full_path = \"%" PRFilePath "\"" | 1194 " full_path = \"%" PRFilePath "\"" |
1043 " target_path = \"%" PRFilePath "\"", | 1195 " target_path = \"%" PRFilePath "\"" |
| 1196 " has download file = %s", |
1044 GetDbHandle(), | 1197 GetDbHandle(), |
1045 GetTotalBytes(), | 1198 GetTotalBytes(), |
1046 GetReceivedBytes(), | 1199 GetReceivedBytes(), |
1047 InterruptReasonDebugString(last_reason_).c_str(), | 1200 InterruptReasonDebugString(last_reason_).c_str(), |
1048 IsPaused() ? 'T' : 'F', | 1201 IsPaused() ? 'T' : 'F', |
1049 DebugSafetyStateString(GetSafetyState()), | 1202 DebugSafetyStateString(GetSafetyState()), |
1050 GetLastModifiedTime().c_str(), | 1203 GetLastModifiedTime().c_str(), |
1051 GetETag().c_str(), | 1204 GetETag().c_str(), |
1052 url_list.c_str(), | 1205 url_list.c_str(), |
1053 GetFullPath().value().c_str(), | 1206 GetFullPath().value().c_str(), |
1054 GetTargetFilePath().value().c_str()); | 1207 GetTargetFilePath().value().c_str(), |
| 1208 download_file_.get() ? "true" : "false"); |
1055 } else { | 1209 } else { |
1056 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); | 1210 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); |
1057 } | 1211 } |
1058 | 1212 |
1059 description += " }"; | 1213 description += " }"; |
1060 | 1214 |
1061 return description; | 1215 return description; |
1062 } | 1216 } |
1063 | 1217 |
1064 bool DownloadItemImpl::AllDataSaved() const { return all_data_saved_; } | 1218 bool DownloadItemImpl::AllDataSaved() const { return all_data_saved_; } |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1154 void DownloadItemImpl::SetOpened(bool opened) { opened_ = opened; } | 1308 void DownloadItemImpl::SetOpened(bool opened) { opened_ = opened; } |
1155 bool DownloadItemImpl::GetOpened() const { return opened_; } | 1309 bool DownloadItemImpl::GetOpened() const { return opened_; } |
1156 const std::string& DownloadItemImpl::GetLastModifiedTime() const { | 1310 const std::string& DownloadItemImpl::GetLastModifiedTime() const { |
1157 return last_modified_time_; | 1311 return last_modified_time_; |
1158 } | 1312 } |
1159 const std::string& DownloadItemImpl::GetETag() const { return etag_; } | 1313 const std::string& DownloadItemImpl::GetETag() const { return etag_; } |
1160 content::DownloadInterruptReason DownloadItemImpl::GetLastReason() const { | 1314 content::DownloadInterruptReason DownloadItemImpl::GetLastReason() const { |
1161 return last_reason_; | 1315 return last_reason_; |
1162 } | 1316 } |
1163 void DownloadItemImpl::MockDownloadOpenForTesting() { open_enabled_ = false; } | 1317 void DownloadItemImpl::MockDownloadOpenForTesting() { open_enabled_ = false; } |
OLD | NEW |