Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: content/browser/download/download_item_impl.cc

Issue 10831302: Download resumption - Preliminary (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fixed content unit tests. Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 // File method ordering: Methods in this file are in the same order 5 // File method ordering: Methods in this file are in the same order
6 // as in download_item_impl.h, with the following exception: The public 6 // as in download_item_impl.h, with the following exception: The public
7 // interfaces DelayedDownloadOpened, OnDownloadTargetDetermined, and 7 // interfaces DelayedDownloadOpened, OnDownloadTargetDetermined, and
8 // OnDownloadCompleting are placed in chronological order with the other 8 // OnDownloadCompleting are placed in chronological order with the other
9 // (private) routines that together define a DownloadItem's state transitions 9 // (private) routines that together define a DownloadItem's state transitions
10 // as the download progresses. See "Download progression cascade" later in 10 // as the download progresses. See "Download progression cascade" later in
(...skipping 28 matching lines...) Expand all
39 #include "content/browser/download/download_file.h" 39 #include "content/browser/download/download_file.h"
40 #include "content/browser/download/download_file_manager.h" 40 #include "content/browser/download/download_file_manager.h"
41 #include "content/browser/download/download_interrupt_reasons_impl.h" 41 #include "content/browser/download/download_interrupt_reasons_impl.h"
42 #include "content/browser/download/download_item_impl_delegate.h" 42 #include "content/browser/download/download_item_impl_delegate.h"
43 #include "content/browser/download/download_request_handle.h" 43 #include "content/browser/download/download_request_handle.h"
44 #include "content/browser/download/download_stats.h" 44 #include "content/browser/download/download_stats.h"
45 #include "content/browser/web_contents/web_contents_impl.h" 45 #include "content/browser/web_contents/web_contents_impl.h"
46 #include "content/public/browser/browser_thread.h" 46 #include "content/public/browser/browser_thread.h"
47 #include "content/public/browser/content_browser_client.h" 47 #include "content/public/browser/content_browser_client.h"
48 #include "content/public/browser/download_persistent_store_info.h" 48 #include "content/public/browser/download_persistent_store_info.h"
49 #include "content/public/browser/download_url_parameters.h"
49 #include "net/base/net_util.h" 50 #include "net/base/net_util.h"
50 51
51 using content::BrowserThread; 52 using content::BrowserThread;
52 using content::DownloadFile; 53 using content::DownloadFile;
53 using content::DownloadId; 54 using content::DownloadId;
54 using content::DownloadItem; 55 using content::DownloadItem;
55 using content::DownloadManager; 56 using content::DownloadManager;
56 using content::DownloadPersistentStoreInfo; 57 using content::DownloadPersistentStoreInfo;
57 using content::WebContents; 58 using content::WebContents;
58 59
59 namespace { 60 namespace {
60 61
61 static void DeleteDownloadedFile(const FilePath& path) { 62 void DeleteDownloadedFile(const FilePath& path) {
62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
63 64
64 // Make sure we only delete files. 65 // Make sure we only delete files.
65 if (!file_util::DirectoryExists(path)) 66 if (!file_util::DirectoryExists(path))
66 file_util::Delete(path, false); 67 file_util::Delete(path, false);
67 } 68 }
68 69
69 const char* DebugSafetyStateString(DownloadItem::SafetyState state) { 70 const char* DebugSafetyStateString(DownloadItem::SafetyState state) {
70 switch (state) { 71 switch (state) {
71 case DownloadItem::SAFE: 72 case DownloadItem::SAFE:
(...skipping 20 matching lines...) Expand all
92 // DownloadRequestHandleInterface calls 93 // DownloadRequestHandleInterface calls
93 virtual WebContents* GetWebContents() const OVERRIDE { 94 virtual WebContents* GetWebContents() const OVERRIDE {
94 return NULL; 95 return NULL;
95 } 96 }
96 virtual DownloadManager* GetDownloadManager() const OVERRIDE { 97 virtual DownloadManager* GetDownloadManager() const OVERRIDE {
97 return NULL; 98 return NULL;
98 } 99 }
99 virtual void PauseRequest() const OVERRIDE {} 100 virtual void PauseRequest() const OVERRIDE {}
100 virtual void ResumeRequest() const OVERRIDE {} 101 virtual void ResumeRequest() const OVERRIDE {}
101 virtual void CancelRequest() const OVERRIDE {} 102 virtual void CancelRequest() const OVERRIDE {}
103 virtual void SetRequestId(int new_request_id) OVERRIDE {}
104 virtual int RequestId() const OVERRIDE { return -1; }
102 virtual std::string DebugString() const OVERRIDE { 105 virtual std::string DebugString() const OVERRIDE {
103 return "Null DownloadRequestHandle"; 106 return "Null DownloadRequestHandle";
104 } 107 }
105 }; 108 };
106 109
107 } // namespace 110 } // namespace
108 111
109 namespace content { 112 namespace content {
110 113
111 // Our download table ID starts at 1, so we use 0 to represent a download that 114 // Our download table ID starts at 1, so we use 0 to represent a download that
112 // has started, but has not yet had its data persisted in the table. We use fake 115 // has started, but has not yet had its data persisted in the table. We use fake
113 // database handles in incognito mode starting at -1 and progressively getting 116 // database handles in incognito mode starting at -1 and progressively getting
114 // more negative. 117 // more negative.
115 // static 118 // static
116 const int DownloadItem::kUninitializedHandle = 0; 119 const int DownloadItem::kUninitializedHandle = 0;
117 120
118 const char DownloadItem::kEmptyFileHash[] = ""; 121 const char DownloadItem::kEmptyFileHash[] = "";
119 122
120 } 123 }
121 124
125 // The maximum number of attempts we will make to resume automatically.
126 const int DownloadItemImpl::kMaxAutoResumeAttempts = 5;
127
122 // Our download table ID starts at 1, so we use 0 to represent a download that 128 // Our download table ID starts at 1, so we use 0 to represent a download that
123 // has started, but has not yet had its data persisted in the table. We use fake 129 // has started, but has not yet had its data persisted in the table. We use fake
124 // database handles in incognito mode starting at -1 and progressively getting 130 // database handles in incognito mode starting at -1 and progressively getting
125 // more negative. 131 // more negative.
126 132
127 // Constructor for reading from the history service. 133 // Constructor for reading from the history service.
128 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, 134 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
129 DownloadId download_id, 135 DownloadId download_id,
130 const DownloadPersistentStoreInfo& info, 136 const DownloadPersistentStoreInfo& info,
131 const net::BoundNetLog& bound_net_log) 137 const net::BoundNetLog& bound_net_log)
(...skipping 10 matching lines...) Expand all
142 bytes_per_sec_(0), 148 bytes_per_sec_(0),
143 last_reason_(content::DOWNLOAD_INTERRUPT_REASON_NONE), 149 last_reason_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
144 start_tick_(base::TimeTicks()), 150 start_tick_(base::TimeTicks()),
145 state_(ExternalToInternalState(info.state)), 151 state_(ExternalToInternalState(info.state)),
146 danger_type_(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), 152 danger_type_(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
147 start_time_(info.start_time), 153 start_time_(info.start_time),
148 end_time_(info.end_time), 154 end_time_(info.end_time),
149 db_handle_(info.db_handle), 155 db_handle_(info.db_handle),
150 delegate_(delegate), 156 delegate_(delegate),
151 is_paused_(false), 157 is_paused_(false),
158 is_resuming_(false),
159 auto_resume_count_(0),
152 open_when_complete_(false), 160 open_when_complete_(false),
153 file_externally_removed_(false), 161 file_externally_removed_(false),
154 safety_state_(SAFE), 162 safety_state_(SAFE),
155 auto_opened_(false), 163 auto_opened_(false),
156 is_persisted_(true), 164 is_persisted_(true),
157 is_temporary_(false), 165 is_temporary_(false),
158 all_data_saved_(false), 166 all_data_saved_(false),
159 opened_(info.opened), 167 opened_(info.opened),
160 open_enabled_(true), 168 open_enabled_(true),
161 delegate_delayed_complete_(false), 169 delegate_delayed_complete_(false),
162 bound_net_log_(bound_net_log), 170 bound_net_log_(bound_net_log),
163 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { 171 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
164 delegate_->Attach(); 172 delegate_->Attach();
165 if (state_ == IN_PROGRESS_INTERNAL) 173 if (state_ == IN_PROGRESS_INTERNAL)
166 state_ = CANCELLED_INTERNAL; 174 state_ = CANCELLED_INTERNAL;
167 if (state_ == COMPLETE_INTERNAL) 175 if (state_ == COMPLETE_INTERNAL)
168 all_data_saved_ = true; 176 all_data_saved_ = true;
169 Init(false /* not actively downloading */, 177 Init(false /* not actively downloading */,
170 download_net_logs::SRC_HISTORY_IMPORT); 178 download_net_logs::SRC_HISTORY_IMPORT);
171 } 179 }
172 180
173 // Constructing for a regular download: 181 // Constructing for a regular download:
174 DownloadItemImpl::DownloadItemImpl( 182 DownloadItemImpl::DownloadItemImpl(
175 DownloadItemImplDelegate* delegate, 183 DownloadItemImplDelegate* delegate,
176 const DownloadCreateInfo& info, 184 const DownloadCreateInfo& info,
177 scoped_ptr<DownloadRequestHandleInterface> request_handle,
178 const net::BoundNetLog& bound_net_log) 185 const net::BoundNetLog& bound_net_log)
179 : request_handle_(request_handle.Pass()), 186 : download_id_(info.download_id),
180 download_id_(info.download_id),
181 target_disposition_( 187 target_disposition_(
182 (info.prompt_user_for_save_location) ? 188 (info.prompt_user_for_save_location) ?
183 TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE), 189 TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE),
184 url_chain_(info.url_chain), 190 url_chain_(info.url_chain),
185 referrer_url_(info.referrer_url), 191 referrer_url_(info.referrer_url),
186 suggested_filename_(UTF16ToUTF8(info.save_info.suggested_name)), 192 suggested_filename_(UTF16ToUTF8(info.save_info.suggested_name)),
187 forced_file_path_(info.save_info.file_path), 193 forced_file_path_(info.save_info.file_path),
188 transition_type_(info.transition_type), 194 transition_type_(info.transition_type),
189 has_user_gesture_(info.has_user_gesture), 195 has_user_gesture_(info.has_user_gesture),
190 content_disposition_(info.content_disposition), 196 content_disposition_(info.content_disposition),
191 mime_type_(info.mime_type), 197 mime_type_(info.mime_type),
192 original_mime_type_(info.original_mime_type), 198 original_mime_type_(info.original_mime_type),
193 referrer_charset_(info.referrer_charset), 199 referrer_charset_(info.referrer_charset),
194 remote_address_(info.remote_address), 200 remote_address_(info.remote_address),
195 total_bytes_(info.total_bytes), 201 total_bytes_(info.total_bytes),
196 received_bytes_(0), 202 received_bytes_(0),
197 bytes_per_sec_(0), 203 bytes_per_sec_(0),
198 last_reason_(content::DOWNLOAD_INTERRUPT_REASON_NONE), 204 last_reason_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
199 start_tick_(base::TimeTicks::Now()), 205 start_tick_(base::TimeTicks::Now()),
200 state_(IN_PROGRESS_INTERNAL), 206 state_(IN_PROGRESS_INTERNAL),
201 danger_type_(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), 207 danger_type_(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
202 start_time_(info.start_time), 208 start_time_(info.start_time),
203 db_handle_(DownloadItem::kUninitializedHandle), 209 db_handle_(DownloadItem::kUninitializedHandle),
204 delegate_(delegate), 210 delegate_(delegate),
205 is_paused_(false), 211 is_paused_(false),
212 is_resuming_(false),
213 auto_resume_count_(0),
206 open_when_complete_(false), 214 open_when_complete_(false),
207 file_externally_removed_(false), 215 file_externally_removed_(false),
208 safety_state_(SAFE), 216 safety_state_(SAFE),
209 auto_opened_(false), 217 auto_opened_(false),
210 is_persisted_(false), 218 is_persisted_(false),
211 is_temporary_(!info.save_info.file_path.empty()), 219 is_temporary_(!info.save_info.file_path.empty()),
212 all_data_saved_(false), 220 all_data_saved_(false),
213 opened_(false), 221 opened_(false),
214 open_enabled_(true), 222 open_enabled_(true),
215 delegate_delayed_complete_(false), 223 delegate_delayed_complete_(false),
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 received_bytes_(0), 259 received_bytes_(0),
252 bytes_per_sec_(0), 260 bytes_per_sec_(0),
253 last_reason_(content::DOWNLOAD_INTERRUPT_REASON_NONE), 261 last_reason_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
254 start_tick_(base::TimeTicks::Now()), 262 start_tick_(base::TimeTicks::Now()),
255 state_(IN_PROGRESS_INTERNAL), 263 state_(IN_PROGRESS_INTERNAL),
256 danger_type_(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), 264 danger_type_(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
257 start_time_(base::Time::Now()), 265 start_time_(base::Time::Now()),
258 db_handle_(DownloadItem::kUninitializedHandle), 266 db_handle_(DownloadItem::kUninitializedHandle),
259 delegate_(delegate), 267 delegate_(delegate),
260 is_paused_(false), 268 is_paused_(false),
269 is_resuming_(false),
270 auto_resume_count_(0),
261 open_when_complete_(false), 271 open_when_complete_(false),
262 file_externally_removed_(false), 272 file_externally_removed_(false),
263 safety_state_(SAFE), 273 safety_state_(SAFE),
264 auto_opened_(false), 274 auto_opened_(false),
265 is_persisted_(false), 275 is_persisted_(false),
266 is_temporary_(false), 276 is_temporary_(false),
267 all_data_saved_(false), 277 all_data_saved_(false),
268 opened_(false), 278 opened_(false),
269 open_enabled_(true), 279 open_enabled_(true),
270 delegate_delayed_complete_(false), 280 delegate_delayed_complete_(false),
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 324
315 safety_state_ = DANGEROUS_BUT_VALIDATED; 325 safety_state_ = DANGEROUS_BUT_VALIDATED;
316 326
317 bound_net_log_.AddEvent( 327 bound_net_log_.AddEvent(
318 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED, 328 net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
319 base::Bind(&download_net_logs::ItemCheckedCallback, 329 base::Bind(&download_net_logs::ItemCheckedCallback,
320 GetDangerType(), GetSafetyState())); 330 GetDangerType(), GetSafetyState()));
321 331
322 UpdateObservers(); 332 UpdateObservers();
323 333
324 delegate_->MaybeCompleteDownload(this); 334 delegate_->MaybeCompleteDownload(download_id_.local());
325 } 335 }
326 336
327 void DownloadItemImpl::TogglePause() { 337 void DownloadItemImpl::TogglePause() {
328 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
329 339
330 DCHECK(state_ == IN_PROGRESS_INTERNAL || state_ == COMPLETING_INTERNAL); 340 DCHECK(IsPartialDownload());
331 if (is_paused_) 341 if (IsInProgress()) {
332 request_handle_->ResumeRequest(); 342 if (is_paused_)
333 else 343 request_handle_->ResumeRequest();
334 request_handle_->PauseRequest(); 344 else
335 is_paused_ = !is_paused_; 345 request_handle_->PauseRequest();
346 is_paused_ = !is_paused_;
347 } else if (IsInterrupted()) {
348 auto_resume_count_ = 0; // User input resets the counter.
349 delegate_->RestartInterruptedDownload(
350 this, content::DownloadUrlParameters::OnStartedCallback());
351 }
352
336 UpdateObservers(); 353 UpdateObservers();
337 } 354 }
338 355
339 void DownloadItemImpl::Cancel(bool user_cancel) { 356 void DownloadItemImpl::Cancel(bool user_cancel) {
340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
341 358
342 last_reason_ = user_cancel ?
343 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED :
344 content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
345
346 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); 359 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
347 if (state_ != IN_PROGRESS_INTERNAL) { 360 if (state_ != IN_PROGRESS_INTERNAL && state_ != INTERRUPTED_INTERNAL) {
348 // Small downloads might be complete before this method has 361 // Small downloads might be complete before this method has
349 // a chance to run. 362 // a chance to run.
350 return; 363 return;
351 } 364 }
352 365
366 last_reason_ = user_cancel ?
367 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED :
368 content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
369
353 download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT); 370 download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT);
354 371
355 TransitionTo(CANCELLED_INTERNAL); 372 TransitionTo(CANCELLED_INTERNAL);
356 delegate_->DownloadStopped(this); 373 delegate_->DownloadStopped(this);
357 } 374 }
358 375
359 void DownloadItemImpl::Delete(DeleteReason reason) { 376 void DownloadItemImpl::Delete(DeleteReason reason) {
360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
361 378
362 switch (reason) { 379 switch (reason) {
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 } 466 }
450 467
451 content::DownloadInterruptReason DownloadItemImpl::GetLastReason() const { 468 content::DownloadInterruptReason DownloadItemImpl::GetLastReason() const {
452 return last_reason_; 469 return last_reason_;
453 } 470 }
454 471
455 bool DownloadItemImpl::IsPaused() const { 472 bool DownloadItemImpl::IsPaused() const {
456 return is_paused_; 473 return is_paused_;
457 } 474 }
458 475
476 bool DownloadItemImpl::IsResuming() const {
477 return is_resuming_;
478 }
479
480 void DownloadItemImpl::SetRequest(
481 scoped_ptr<DownloadRequestHandleInterface> request_handle) {
482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
483 request_handle_ = request_handle.Pass();
484 }
485
486 DownloadItem::ResumeMode DownloadItemImpl::CanResumeInterrupted() const {
487 if (!IsInterrupted() || !is_persisted_)
488 return RESUME_MODE_INVALID;
489
490 ResumeMode mode = RESUME_MODE_INVALID;
491
492 switch(last_reason_) {
493 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
494 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
495 mode = RESUME_MODE_IMMEDIATE_CONTINUE; // Continue immediately.
496 break;
497
498 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION:
499 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
500 mode = RESUME_MODE_IMMEDIATE_RESTART; // Restart immediately.
501 break;
502
503 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
504 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
505 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
506 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
507 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
508 case content::DOWNLOAD_INTERRUPT_REASON_CRASH:
509 mode = RESUME_MODE_USER_CONTINUE; // Continue via user input.
510 break;
511
512 case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
513 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
514 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
515 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
516 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
517 mode = RESUME_MODE_USER_RESTART; // Restart via user input.
518 break;
519
520 case content::DOWNLOAD_INTERRUPT_REASON_NONE:
521 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
522 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
523 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
524 break;
525 }
526
527 // Check if we have exhausted the number of automatic retry attempts.
528 if (auto_resume_count_ >= kMaxAutoResumeAttempts) {
529 if (mode == RESUME_MODE_IMMEDIATE_CONTINUE)
530 mode = RESUME_MODE_USER_CONTINUE;
531 else if (mode == RESUME_MODE_IMMEDIATE_RESTART)
532 mode = RESUME_MODE_USER_RESTART;
533 }
534
535 return mode;
536 }
537
538 void DownloadItemImpl::AutoResumeIfValid() {
539 ResumeMode mode = CanResumeInterrupted();
540
541 if ((mode == RESUME_MODE_IMMEDIATE_RESTART) ||
542 (mode == RESUME_MODE_IMMEDIATE_CONTINUE)) {
543 if (mode == RESUME_MODE_IMMEDIATE_RESTART) {
544 received_bytes_ = 0; // Restart instead of continuing.
545 hash_state_ = "";
546 last_modified_time_ = "";
547 etag_ = "";
548 }
549
550 auto_resume_count_++;
551
552 delegate_->RestartInterruptedDownload(
553 this, content::DownloadUrlParameters::OnStartedCallback());
554 }
555 }
556
459 bool DownloadItemImpl::IsTemporary() const { 557 bool DownloadItemImpl::IsTemporary() const {
460 return is_temporary_; 558 return is_temporary_;
461 } 559 }
462 560
463 bool DownloadItemImpl::IsPersisted() const { 561 bool DownloadItemImpl::IsPersisted() const {
464 return is_persisted_; 562 return is_persisted_;
465 } 563 }
466 564
467 // TODO(ahendrickson) -- Move |INTERRUPTED| from |IsCancelled()| to
468 // |IsPartialDownload()|, when resuming interrupted downloads is implemented.
469 bool DownloadItemImpl::IsPartialDownload() const { 565 bool DownloadItemImpl::IsPartialDownload() const {
470 return InternalToExternalState(state_) == IN_PROGRESS; 566 DownloadState state = InternalToExternalState(state_);
567 return (state == IN_PROGRESS) || (state == INTERRUPTED);
benjhayden 2012/10/15 17:59:37 Have you audited all the callers of IsPartialDownl
471 } 568 }
472 569
473 bool DownloadItemImpl::IsInProgress() const { 570 bool DownloadItemImpl::IsInProgress() const {
474 return InternalToExternalState(state_) == IN_PROGRESS; 571 return InternalToExternalState(state_) == IN_PROGRESS;
475 } 572 }
476 573
477 bool DownloadItemImpl::IsCancelled() const { 574 bool DownloadItemImpl::IsCancelled() const {
478 DownloadState external_state = InternalToExternalState(state_); 575 return InternalToExternalState(state_) == CANCELLED;
479 return external_state == CANCELLED || external_state == INTERRUPTED;
benjhayden 2012/10/15 17:59:37 Have you audited all the callers of IsCancelled()
480 } 576 }
481 577
482 bool DownloadItemImpl::IsInterrupted() const { 578 bool DownloadItemImpl::IsInterrupted() const {
483 return InternalToExternalState(state_) == INTERRUPTED; 579 return InternalToExternalState(state_) == INTERRUPTED;
484 } 580 }
485 581
486 bool DownloadItemImpl::IsComplete() const { 582 bool DownloadItemImpl::IsComplete() const {
487 return InternalToExternalState(state_) == COMPLETE; 583 return InternalToExternalState(state_) == COMPLETE;
488 } 584 }
489 585
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 } 753 }
658 754
659 bool DownloadItemImpl::CanShowInFolder() { 755 bool DownloadItemImpl::CanShowInFolder() {
660 return state_ != CANCELLED_INTERNAL && !file_externally_removed_; 756 return state_ != CANCELLED_INTERNAL && !file_externally_removed_;
661 } 757 }
662 758
663 bool DownloadItemImpl::CanOpenDownload() { 759 bool DownloadItemImpl::CanOpenDownload() {
664 return !file_externally_removed_; 760 return !file_externally_removed_;
665 } 761 }
666 762
763 bool DownloadItemImpl::CanResumeDownload() const {
764 // Do not allow interrupted downloads to be resumed until the target name
765 // has been determined, and the user has validated any dangerous items.
766 // TODO(rdsmith) -- Add a state indicating that filename determination has
767 // occurred.
768 if (GetTargetFilePath().empty())
769 return false;
770
771 if (GetSafetyState() == DANGEROUS)
772 return false;
773
774 return IsInProgress() ||
775 (CanResumeInterrupted() != DownloadItem::RESUME_MODE_INVALID);
776 }
777
667 bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() { 778 bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() {
668 return delegate_->ShouldOpenFileBasedOnExtension(GetUserVerifiedFilePath()); 779 return delegate_->ShouldOpenFileBasedOnExtension(GetUserVerifiedFilePath());
669 } 780 }
670 781
671 bool DownloadItemImpl::GetOpenWhenComplete() const { 782 bool DownloadItemImpl::GetOpenWhenComplete() const {
672 return open_when_complete_; 783 return open_when_complete_;
673 } 784 }
674 785
675 bool DownloadItemImpl::GetAutoOpened() { 786 bool DownloadItemImpl::GetAutoOpened() {
676 return auto_opened_; 787 return auto_opened_;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 } 864 }
754 } 865 }
755 866
756 if (verbose) { 867 if (verbose) {
757 description += base::StringPrintf( 868 description += base::StringPrintf(
758 " db_handle = %" PRId64 869 " db_handle = %" PRId64
759 " total = %" PRId64 870 " total = %" PRId64
760 " received = %" PRId64 871 " received = %" PRId64
761 " reason = %s" 872 " reason = %s"
762 " paused = %c" 873 " paused = %c"
874 " resuming = %c"
875 " resume_mode = %s"
763 " safety = %s" 876 " safety = %s"
877 " all_data_saved = %c"
878 " persisted = %c"
764 " last_modified = '%s'" 879 " last_modified = '%s'"
765 " etag = '%s'" 880 " etag = '%s'"
766 " url_chain = \n\t\"%s\"\n\t" 881 " url_chain = \n\t\"%s\"\n\t"
767 " full_path = \"%" PRFilePath "\"" 882 " full_path = \"%" PRFilePath "\""
768 " target_path = \"%" PRFilePath "\"", 883 " target_path = \"%" PRFilePath "\"",
769 GetDbHandle(), 884 GetDbHandle(),
770 GetTotalBytes(), 885 GetTotalBytes(),
771 GetReceivedBytes(), 886 GetReceivedBytes(),
772 InterruptReasonDebugString(last_reason_).c_str(), 887 InterruptReasonDebugString(last_reason_).c_str(),
773 IsPaused() ? 'T' : 'F', 888 IsPaused() ? 'T' : 'F',
889 IsResuming() ? 'T' : 'F',
890 DebugResumeModeString(CanResumeInterrupted()),
774 DebugSafetyStateString(GetSafetyState()), 891 DebugSafetyStateString(GetSafetyState()),
892 AllDataSaved() ? 'T' : 'F',
893 IsPersisted() ? 'T' : 'F',
775 GetLastModifiedTime().c_str(), 894 GetLastModifiedTime().c_str(),
776 GetETag().c_str(), 895 GetETag().c_str(),
777 url_list.c_str(), 896 url_list.c_str(),
778 GetFullPath().value().c_str(), 897 GetFullPath().value().c_str(),
779 GetTargetFilePath().value().c_str()); 898 GetTargetFilePath().value().c_str());
780 } else { 899 } else {
781 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); 900 description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
782 } 901 }
783 902
784 description += " }"; 903 description += " }";
785 904
786 return description; 905 return description;
787 } 906 }
788 907
789 void DownloadItemImpl::MockDownloadOpenForTesting() { 908 void DownloadItemImpl::MockDownloadOpenForTesting() {
790 open_enabled_ = false; 909 open_enabled_ = false;
791 } 910 }
792 911
793 void DownloadItemImpl::NotifyRemoved() { 912 void DownloadItemImpl::NotifyRemoved() {
794 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this)); 913 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this));
795 } 914 }
796 915
797 void DownloadItemImpl::OnDownloadedFileRemoved() { 916 void DownloadItemImpl::OnDownloadedFileRemoved() {
798 file_externally_removed_ = true; 917 file_externally_removed_ = true;
799 UpdateObservers(); 918 UpdateObservers();
919 delegate_->MaybeCompleteDownload(download_id_.local());
benjhayden 2012/10/15 17:59:37 Sorry, what's this doing? I looked in download_man
800 } 920 }
801 921
802 void DownloadItemImpl::OffThreadCancel() { 922 void DownloadItemImpl::OffThreadCancel() {
803 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 923 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
804 request_handle_->CancelRequest(); 924 request_handle_->CancelRequest();
805 925
806 BrowserThread::PostTask( 926 BrowserThread::PostTask(
807 BrowserThread::FILE, FROM_HERE, 927 BrowserThread::FILE, FROM_HERE,
808 base::Bind(&DownloadFileManager::CancelDownload, 928 base::Bind(&DownloadFileManager::CancelDownload,
809 delegate_->GetDownloadFileManager(), download_id_)); 929 delegate_->GetDownloadFileManager(), download_id_));
810 } 930 }
811 931
932 void DownloadItemImpl::OffThreadInterrupt() {
933 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
934 request_handle_->CancelRequest();
935
936 BrowserThread::PostTask(
937 BrowserThread::FILE,
938 FROM_HERE,
939 base::Bind(&DownloadFileManager::InterruptDownload,
940 delegate_->GetDownloadFileManager(),
941 download_id_,
942 base::Closure()));
943 }
944
812 // An error occurred somewhere. 945 // An error occurred somewhere.
813 void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) { 946 void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) {
814 // Somewhat counter-intuitively, it is possible for us to receive an 947 // Somewhat counter-intuitively, it is possible for us to receive an
815 // interrupt after we've already been interrupted. The generation of 948 // interrupt after we've already been interrupted. The generation of
816 // interrupts from the file thread Renames and the generation of 949 // interrupts from the file thread Renames and the generation of
817 // interrupts from disk writes go through two different mechanisms (driven 950 // interrupts from disk writes go through two different mechanisms (driven
818 // by rename requests from UI thread and by write requests from IO thread, 951 // by rename requests from UI thread and by write requests from IO thread,
819 // respectively), and since we choose not to keep state on the File thread, 952 // respectively), and since we choose not to keep state on the File thread,
820 // this is the place where the races collide. It's also possible for 953 // this is the place where the races collide. It's also possible for
821 // interrupts to race with cancels. 954 // interrupts to race with cancels.
822 955
823 // Whatever happens, the first one to hit the UI thread wins. 956 // Whatever happens, the first one to hit the UI thread wins.
824 if (state_ != IN_PROGRESS_INTERNAL) 957 if (state_ != IN_PROGRESS_INTERNAL)
825 return; 958 return;
826 959
827 last_reason_ = reason; 960 last_reason_ = reason;
961 is_resuming_ = false;
828 TransitionTo(INTERRUPTED_INTERNAL); 962 TransitionTo(INTERRUPTED_INTERNAL);
829 download_stats::RecordDownloadInterrupted( 963 download_stats::RecordDownloadInterrupted(
830 reason, received_bytes_, total_bytes_); 964 reason, received_bytes_, total_bytes_);
831 delegate_->DownloadStopped(this); 965 delegate_->DownloadStopped(this);
966
967 AutoResumeIfValid();
968 }
969
970 void DownloadItemImpl::Resume(
971 scoped_ptr<DownloadRequestHandleInterface> req_handle) {
972 DVLOG(20) << __FUNCTION__ << "() " << DebugString(true);
973 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
974
975 if (state_ != INTERRUPTED_INTERNAL)
976 return;
977 request_handle_ = req_handle.Pass();
978 is_resuming_ = true;
979 TransitionTo(IN_PROGRESS_INTERNAL);
832 } 980 }
833 981
834 void DownloadItemImpl::SetTotalBytes(int64 total_bytes) { 982 void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
835 total_bytes_ = total_bytes; 983 total_bytes_ = total_bytes;
836 } 984 }
837 985
838 // Updates from the download thread may have been posted while this download 986 // Updates from the download thread may have been posted while this download
839 // was being cancelled in the UI thread, so we'll accept them unless we're 987 // was being cancelled in the UI thread, so we'll accept them unless we're
840 // complete. 988 // complete.
841 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, 989 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far,
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
1007 } else { 1155 } else {
1008 SetFullPath(full_path); 1156 SetFullPath(full_path);
1009 UpdateObservers(); 1157 UpdateObservers();
1010 } 1158 }
1011 1159
1012 delegate_->DownloadRenamedToIntermediateName(this); 1160 delegate_->DownloadRenamedToIntermediateName(this);
1013 } 1161 }
1014 1162
1015 void DownloadItemImpl::MaybeCompleteDownload() { 1163 void DownloadItemImpl::MaybeCompleteDownload() {
1016 // TODO(rdsmith): Move logic for this function here. 1164 // TODO(rdsmith): Move logic for this function here.
1017 delegate_->MaybeCompleteDownload(this); 1165 delegate_->MaybeCompleteDownload(download_id_.local());
1018 } 1166 }
1019 1167
1020 // Called by DownloadManagerImpl::MaybeCompleteDownload() when it has 1168 // Called by DownloadManagerImpl::MaybeCompleteDownload() when it has
1021 // determined that the download is ready for completion. 1169 // determined that the download is ready for completion.
1022 void DownloadItemImpl::OnDownloadCompleting() { 1170 void DownloadItemImpl::OnDownloadCompleting() {
1023 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1024 1172
1025 if (state_ != IN_PROGRESS_INTERNAL) 1173 if (state_ != IN_PROGRESS_INTERNAL)
1026 return; 1174 return;
1027 1175
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
1262 case CANCELLED: 1410 case CANCELLED:
1263 return CANCELLED_INTERNAL; 1411 return CANCELLED_INTERNAL;
1264 case INTERRUPTED: 1412 case INTERRUPTED:
1265 return INTERRUPTED_INTERNAL; 1413 return INTERRUPTED_INTERNAL;
1266 default: 1414 default:
1267 NOTREACHED(); 1415 NOTREACHED();
1268 } 1416 }
1269 return MAX_DOWNLOAD_INTERNAL_STATE; 1417 return MAX_DOWNLOAD_INTERNAL_STATE;
1270 } 1418 }
1271 1419
1420 const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
1421 return bound_net_log_;
1422 }
1423
1272 const char* DownloadItemImpl::DebugDownloadStateString( 1424 const char* DownloadItemImpl::DebugDownloadStateString(
1273 DownloadInternalState state) { 1425 DownloadInternalState state) {
1274 switch (state) { 1426 switch (state) {
1275 case IN_PROGRESS_INTERNAL: 1427 case IN_PROGRESS_INTERNAL:
1276 return "IN_PROGRESS"; 1428 return "IN_PROGRESS";
1277 case COMPLETING_INTERNAL: 1429 case COMPLETING_INTERNAL:
1278 return "COMPLETING"; 1430 return "COMPLETING";
1279 case COMPLETE_INTERNAL: 1431 case COMPLETE_INTERNAL:
1280 return "COMPLETE"; 1432 return "COMPLETE";
1281 case CANCELLED_INTERNAL: 1433 case CANCELLED_INTERNAL:
1282 return "CANCELLED"; 1434 return "CANCELLED";
1283 case INTERRUPTED_INTERNAL: 1435 case INTERRUPTED_INTERNAL:
1284 return "INTERRUPTED"; 1436 return "INTERRUPTED";
1285 default: 1437 default:
1286 NOTREACHED() << "Unknown download state " << state; 1438 NOTREACHED() << "Unknown download state " << state;
1287 return "unknown"; 1439 return "unknown";
1288 }; 1440 };
1289 } 1441 }
1442
1443 const char* DownloadItemImpl::DebugResumeModeString(
1444 DownloadItem::ResumeMode mode) {
1445 switch (mode) {
1446 case DownloadItem::RESUME_MODE_INVALID:
1447 return "INVALID";
1448 case DownloadItem::RESUME_MODE_IMMEDIATE_CONTINUE:
1449 return "IMMEDIATE_CONTINUE";
1450 case DownloadItem::RESUME_MODE_IMMEDIATE_RESTART:
1451 return "IMMEDIATE_RESTART";
1452 case DownloadItem::RESUME_MODE_USER_CONTINUE:
1453 return "USER_CONTINUE";
1454 case DownloadItem::RESUME_MODE_USER_RESTART:
1455 return "USER_RESTART";
1456 default:
1457 NOTREACHED() << "Unknown resume mode " << mode;
1458 return "unknown";
1459 }
1460 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698