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

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

Issue 11571025: Initial CL for Downloads resumption. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Ready for review. Created 7 years, 12 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 | Annotate | Revision Log
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 as 5 // File method ordering: Methods in this file are in the same order as
6 // in download_item_impl.h, with the following exception: The public 6 // in download_item_impl.h, with the following exception: The public
7 // interface Start is placed in chronological order with the other 7 // interface Start is placed in chronological order with the other
8 // (private) routines that together define a DownloadItem's state 8 // (private) routines that together define a DownloadItem's state
9 // transitions as the download progresses. See "Download progression 9 // transitions as the download progresses. See "Download progression
10 // cascade" later in this file. 10 // cascade" later in this file.
11 11
12 // A regular DownloadItem (created for a download in this session of the 12 // A regular DownloadItem (created for a download in this session of the
13 // browser) normally goes through the following states: 13 // browser) normally goes through the following states:
14 // * Created (when download starts) 14 // * Created (when download starts)
15 // * Destination filename determined 15 // * Destination filename determined
16 // * Entered into the history database. 16 // * Entered into the history database.
17 // * Made visible in the download shelf. 17 // * Made visible in the download shelf.
18 // * All the data is saved. Note that the actual data download occurs 18 // * All the data is saved. Note that the actual data download occurs
19 // in parallel with the above steps, but until those steps are 19 // in parallel with the above steps, but until those steps are
20 // complete, the state of the data save will be ignored. 20 // complete, the state of the data save will be ignored.
21 // * Download file is renamed to its final name, and possibly 21 // * Download file is renamed to its final name, and possibly
22 // auto-opened. 22 // auto-opened.
23 23
24 #include "content/browser/download/download_item_impl.h" 24 #include "content/browser/download/download_item_impl.h"
25 25
26 #include <vector> 26 #include <vector>
27 27
28 #include "base/basictypes.h" 28 #include "base/basictypes.h"
29 #include "base/bind.h" 29 #include "base/bind.h"
30 #include "base/command_line.h"
30 #include "base/file_util.h" 31 #include "base/file_util.h"
31 #include "base/format_macros.h" 32 #include "base/format_macros.h"
32 #include "base/logging.h" 33 #include "base/logging.h"
33 #include "base/metrics/histogram.h" 34 #include "base/metrics/histogram.h"
34 #include "base/stl_util.h" 35 #include "base/stl_util.h"
35 #include "base/stringprintf.h" 36 #include "base/stringprintf.h"
36 #include "base/utf_string_conversions.h" 37 #include "base/utf_string_conversions.h"
37 #include "content/browser/download/download_create_info.h" 38 #include "content/browser/download/download_create_info.h"
38 #include "content/browser/download/download_file.h" 39 #include "content/browser/download/download_file.h"
39 #include "content/browser/download/download_interrupt_reasons_impl.h" 40 #include "content/browser/download/download_interrupt_reasons_impl.h"
40 #include "content/browser/download/download_item_impl_delegate.h" 41 #include "content/browser/download/download_item_impl_delegate.h"
41 #include "content/browser/download/download_request_handle.h" 42 #include "content/browser/download/download_request_handle.h"
42 #include "content/browser/download/download_stats.h" 43 #include "content/browser/download/download_stats.h"
44 #include "content/browser/renderer_host/render_view_host_impl.h"
43 #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_context.h"
44 #include "content/public/browser/browser_thread.h" 47 #include "content/public/browser/browser_thread.h"
45 #include "content/public/browser/content_browser_client.h" 48 #include "content/public/browser/content_browser_client.h"
49 #include "content/public/browser/download_interrupt_reasons.h"
50 #include "content/public/browser/download_url_parameters.h"
51 #include "content/public/common/content_switches.h"
52 #include "content/public/common/referrer.h"
46 #include "net/base/net_util.h" 53 #include "net/base/net_util.h"
47 54
48 namespace content { 55 namespace content {
56
49 namespace { 57 namespace {
50 58
51 static void DeleteDownloadedFile(const FilePath& path) { 59 void DeleteDownloadedFile(const FilePath& path) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
53 61
54 // Make sure we only delete files. 62 // Make sure we only delete files.
55 if (!file_util::DirectoryExists(path)) 63 if (!file_util::DirectoryExists(path))
56 file_util::Delete(path, false); 64 file_util::Delete(path, false);
57 } 65 }
58 66
59 const char* DebugSafetyStateString(DownloadItem::SafetyState state) { 67 const char* DebugSafetyStateString(DownloadItem::SafetyState state) {
60 switch (state) { 68 switch (state) {
61 case DownloadItem::SAFE: 69 case DownloadItem::SAFE:
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 112
105 static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) { 113 static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
107 download_file->Cancel(); 115 download_file->Cancel();
108 } 116 }
109 117
110 } // namespace 118 } // namespace
111 119
112 const char DownloadItem::kEmptyFileHash[] = ""; 120 const char DownloadItem::kEmptyFileHash[] = "";
113 121
122 // The maximum number of attempts we will make to resume automatically.
123 const int DownloadItemImpl::kMaxAutoResumeAttempts = 5;
124
114 // Constructor for reading from the history service. 125 // Constructor for reading from the history service.
115 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, 126 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
116 DownloadId download_id, 127 DownloadId download_id,
117 const FilePath& path, 128 const FilePath& path,
118 const GURL& url, 129 const GURL& url,
119 const GURL& referrer_url, 130 const GURL& referrer_url,
120 const base::Time& start_time, 131 const base::Time& start_time,
121 const base::Time& end_time, 132 const base::Time& end_time,
122 int64 received_bytes, 133 int64 received_bytes,
123 int64 total_bytes, 134 int64 total_bytes,
(...skipping 13 matching lines...) Expand all
137 received_bytes_(received_bytes), 148 received_bytes_(received_bytes),
138 bytes_per_sec_(0), 149 bytes_per_sec_(0),
139 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE), 150 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
140 start_tick_(base::TimeTicks()), 151 start_tick_(base::TimeTicks()),
141 state_(ExternalToInternalState(state)), 152 state_(ExternalToInternalState(state)),
142 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), 153 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
143 start_time_(start_time), 154 start_time_(start_time),
144 end_time_(end_time), 155 end_time_(end_time),
145 delegate_(delegate), 156 delegate_(delegate),
146 is_paused_(false), 157 is_paused_(false),
158 auto_resume_count_(0),
147 open_when_complete_(false), 159 open_when_complete_(false),
148 file_externally_removed_(false), 160 file_externally_removed_(false),
149 safety_state_(SAFE), 161 safety_state_(SAFE),
150 auto_opened_(false), 162 auto_opened_(false),
151 is_temporary_(false), 163 is_temporary_(false),
152 all_data_saved_(false), 164 all_data_saved_(false),
153 opened_(opened), 165 opened_(opened),
154 open_enabled_(true), 166 open_enabled_(true),
155 delegate_delayed_complete_(false), 167 delegate_delayed_complete_(false),
156 bound_net_log_(bound_net_log), 168 bound_net_log_(bound_net_log),
157 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { 169 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
158 delegate_->Attach(); 170 delegate_->Attach();
159 if (state_ == IN_PROGRESS_INTERNAL) 171 if (state_ == IN_PROGRESS_INTERNAL)
160 state_ = CANCELLED_INTERNAL; 172 state_ = CANCELLED_INTERNAL;
161 if (state_ == COMPLETE_INTERNAL) 173 if (state_ == COMPLETE_INTERNAL)
162 all_data_saved_ = true; 174 all_data_saved_ = true;
163 Init(false /* not actively downloading */, SRC_HISTORY_IMPORT); 175 Init(false /* not actively downloading */, SRC_HISTORY_IMPORT);
164 } 176 }
165 177
166 // Constructing for a regular download: 178 // Constructing for a regular download:
167 DownloadItemImpl::DownloadItemImpl( 179 DownloadItemImpl::DownloadItemImpl(
168 DownloadItemImplDelegate* delegate, 180 DownloadItemImplDelegate* delegate,
169 const DownloadCreateInfo& info, 181 const DownloadCreateInfo& info,
170 scoped_ptr<DownloadRequestHandleInterface> request_handle,
171 const net::BoundNetLog& bound_net_log) 182 const net::BoundNetLog& bound_net_log)
172 : is_save_package_download_(false), 183 : is_save_package_download_(false),
173 request_handle_(request_handle.Pass()),
174 download_id_(info.download_id), 184 download_id_(info.download_id),
175 target_disposition_( 185 target_disposition_(
176 (info.save_info->prompt_for_save_location) ? 186 (info.save_info->prompt_for_save_location) ?
177 TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE), 187 TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE),
178 url_chain_(info.url_chain), 188 url_chain_(info.url_chain),
179 referrer_url_(info.referrer_url), 189 referrer_url_(info.referrer_url),
180 suggested_filename_(UTF16ToUTF8(info.save_info->suggested_name)), 190 suggested_filename_(UTF16ToUTF8(info.save_info->suggested_name)),
181 forced_file_path_(info.save_info->file_path), 191 forced_file_path_(info.save_info->file_path),
182 transition_type_(info.transition_type), 192 transition_type_(info.transition_type),
183 has_user_gesture_(info.has_user_gesture), 193 has_user_gesture_(info.has_user_gesture),
184 content_disposition_(info.content_disposition), 194 content_disposition_(info.content_disposition),
185 mime_type_(info.mime_type), 195 mime_type_(info.mime_type),
186 original_mime_type_(info.original_mime_type), 196 original_mime_type_(info.original_mime_type),
187 remote_address_(info.remote_address), 197 remote_address_(info.remote_address),
188 total_bytes_(info.total_bytes), 198 total_bytes_(info.total_bytes),
189 received_bytes_(0), 199 received_bytes_(0),
190 bytes_per_sec_(0), 200 bytes_per_sec_(0),
191 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE), 201 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
192 start_tick_(base::TimeTicks::Now()), 202 start_tick_(base::TimeTicks::Now()),
193 state_(IN_PROGRESS_INTERNAL), 203 state_(IN_PROGRESS_INTERNAL),
194 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), 204 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
195 start_time_(info.start_time), 205 start_time_(info.start_time),
196 delegate_(delegate), 206 delegate_(delegate),
197 is_paused_(false), 207 is_paused_(false),
208 auto_resume_count_(0),
198 open_when_complete_(false), 209 open_when_complete_(false),
199 file_externally_removed_(false), 210 file_externally_removed_(false),
200 safety_state_(SAFE), 211 safety_state_(SAFE),
201 auto_opened_(false), 212 auto_opened_(false),
202 is_temporary_(!info.save_info->file_path.empty()), 213 is_temporary_(!info.save_info->file_path.empty()),
203 all_data_saved_(false), 214 all_data_saved_(false),
204 opened_(false), 215 opened_(false),
205 open_enabled_(true), 216 open_enabled_(true),
206 delegate_delayed_complete_(false), 217 delegate_delayed_complete_(false),
207 bound_net_log_(bound_net_log), 218 bound_net_log_(bound_net_log),
208 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { 219 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
209 delegate_->Attach(); 220 delegate_->Attach();
210 Init(true /* actively downloading */, SRC_NEW_DOWNLOAD); 221 Init(true /* actively downloading */, SRC_ACTIVE_DOWNLOAD);
211 222
212 // Link the event sources. 223 // Link the event sources.
213 bound_net_log_.AddEvent( 224 bound_net_log_.AddEvent(
214 net::NetLog::TYPE_DOWNLOAD_URL_REQUEST, 225 net::NetLog::TYPE_DOWNLOAD_URL_REQUEST,
215 info.request_bound_net_log.source().ToEventParametersCallback()); 226 info.request_bound_net_log.source().ToEventParametersCallback());
216 227
217 info.request_bound_net_log.AddEvent( 228 info.request_bound_net_log.AddEvent(
218 net::NetLog::TYPE_DOWNLOAD_STARTED, 229 net::NetLog::TYPE_DOWNLOAD_STARTED,
219 bound_net_log_.source().ToEventParametersCallback()); 230 bound_net_log_.source().ToEventParametersCallback());
220 } 231 }
(...skipping 20 matching lines...) Expand all
241 total_bytes_(0), 252 total_bytes_(0),
242 received_bytes_(0), 253 received_bytes_(0),
243 bytes_per_sec_(0), 254 bytes_per_sec_(0),
244 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE), 255 last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
245 start_tick_(base::TimeTicks::Now()), 256 start_tick_(base::TimeTicks::Now()),
246 state_(IN_PROGRESS_INTERNAL), 257 state_(IN_PROGRESS_INTERNAL),
247 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), 258 danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
248 start_time_(base::Time::Now()), 259 start_time_(base::Time::Now()),
249 delegate_(delegate), 260 delegate_(delegate),
250 is_paused_(false), 261 is_paused_(false),
262 auto_resume_count_(0),
251 open_when_complete_(false), 263 open_when_complete_(false),
252 file_externally_removed_(false), 264 file_externally_removed_(false),
253 safety_state_(SAFE), 265 safety_state_(SAFE),
254 auto_opened_(false), 266 auto_opened_(false),
255 is_temporary_(false), 267 is_temporary_(false),
256 all_data_saved_(false), 268 all_data_saved_(false),
257 opened_(false), 269 opened_(false),
258 open_enabled_(true), 270 open_enabled_(true),
259 delegate_delayed_complete_(false), 271 delegate_delayed_complete_(false),
260 bound_net_log_(bound_net_log), 272 bound_net_log_(bound_net_log),
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 base::Bind(&ItemCheckedNetLogCallback, 326 base::Bind(&ItemCheckedNetLogCallback,
315 GetDangerType(), GetSafetyState())); 327 GetDangerType(), GetSafetyState()));
316 328
317 UpdateObservers(); 329 UpdateObservers();
318 330
319 MaybeCompleteDownload(); 331 MaybeCompleteDownload();
320 } 332 }
321 333
322 void DownloadItemImpl::TogglePause() { 334 void DownloadItemImpl::TogglePause() {
323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
324 DCHECK(state_ == IN_PROGRESS_INTERNAL || state_ == COMPLETING_INTERNAL); 336 DCHECK(IsPartialDownload());
325 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true); 337 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
326 338
327 // Ignore pauses when we've passed the commit point. 339 // Ignore pauses when we've passed the commit point.
328 if (state_ == COMPLETING_INTERNAL) 340 if (state_ == COMPLETING_INTERNAL)
329 return; 341 return;
330 342
331 if (is_paused_) 343 if (IsInProgress()) {
332 request_handle_->ResumeRequest(); 344 if (is_paused_)
333 else 345 request_handle_->ResumeRequest();
334 request_handle_->PauseRequest(); 346 else
335 is_paused_ = !is_paused_; 347 request_handle_->PauseRequest();
348 is_paused_ = !is_paused_;
349 } else if (IsInterrupted()) {
350 auto_resume_count_ = 0; // User input resets the counter.
351 ResumeInterruptedDownload();
352 }
353
336 UpdateObservers(); 354 UpdateObservers();
337 } 355 }
338 356
339 void DownloadItemImpl::Cancel(bool user_cancel) { 357 void DownloadItemImpl::Cancel(bool user_cancel) {
340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
341 359
342 last_reason_ = user_cancel ?
343 DOWNLOAD_INTERRUPT_REASON_USER_CANCELED :
344 DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
345
346 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); 360 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
347 if (state_ != IN_PROGRESS_INTERNAL) { 361 if (state_ != IN_PROGRESS_INTERNAL && state_ != INTERRUPTED_INTERNAL) {
348 // Small downloads might be complete before this method has 362 // Small downloads might be complete before this method has
349 // a chance to run. 363 // a chance to run.
350 return; 364 return;
351 } 365 }
352 366
367 last_reason_ = user_cancel ?
368 DOWNLOAD_INTERRUPT_REASON_USER_CANCELED :
369 DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
370
353 RecordDownloadCount(CANCELLED_COUNT); 371 RecordDownloadCount(CANCELLED_COUNT);
354 372
355 TransitionTo(CANCELLED_INTERNAL); 373 TransitionTo(CANCELLED_INTERNAL);
356 374
357 CancelDownloadFile(); 375 CancelDownloadFile();
358 376
359 // Cancel the originating URL request. 377 // Cancel the originating URL request.
360 request_handle_->CancelRequest(); 378 request_handle_->CancelRequest();
361 } 379 }
362 380
363 void DownloadItemImpl::Delete(DeleteReason reason) { 381 void DownloadItemImpl::Delete(DeleteReason reason) {
382 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
365 384
366 switch (reason) { 385 switch (reason) {
367 case DELETE_DUE_TO_USER_DISCARD: 386 case DELETE_DUE_TO_USER_DISCARD:
368 UMA_HISTOGRAM_ENUMERATION( 387 UMA_HISTOGRAM_ENUMERATION(
369 "Download.UserDiscard", GetDangerType(), 388 "Download.UserDiscard", GetDangerType(),
370 DOWNLOAD_DANGER_TYPE_MAX); 389 DOWNLOAD_DANGER_TYPE_MAX);
371 break; 390 break;
372 case DELETE_DUE_TO_BROWSER_SHUTDOWN: 391 case DELETE_DUE_TO_BROWSER_SHUTDOWN:
373 UMA_HISTOGRAM_ENUMERATION( 392 UMA_HISTOGRAM_ENUMERATION(
374 "Download.Discard", GetDangerType(), 393 "Download.Discard", GetDangerType(),
375 DOWNLOAD_DANGER_TYPE_MAX); 394 DOWNLOAD_DANGER_TYPE_MAX);
376 break; 395 break;
377 default: 396 default:
378 NOTREACHED(); 397 NOTREACHED();
379 } 398 }
380 399
381 // Delete the file if it exists and is not owned by a DownloadFile object. 400 // Delete the file if it exists and is not owned by a DownloadFile object.
382 // (In the latter case the DownloadFile object will delete it on cancel.) 401 // (In the latter case the DownloadFile object will delete it on cancel.)
383 if (!current_path_.empty() && download_file_.get() == NULL) { 402 if (!current_path_.empty() && download_file_.get() == NULL) {
384 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 403 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
385 base::Bind(&DeleteDownloadedFile, current_path_)); 404 base::Bind(&DeleteDownloadedFile, current_path_));
386 } 405 }
387 Remove(); 406 Remove();
388 // We have now been deleted. 407 // We have now been deleted.
389 } 408 }
390 409
391 void DownloadItemImpl::Remove() { 410 void DownloadItemImpl::Remove() {
411 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
393 413
394 delegate_->AssertStateConsistent(this); 414 delegate_->AssertStateConsistent(this);
395 Cancel(true); 415 Cancel(true);
396 delegate_->AssertStateConsistent(this); 416 delegate_->AssertStateConsistent(this);
397 417
398 NotifyRemoved(); 418 NotifyRemoved();
399 delegate_->DownloadRemoved(this); 419 delegate_->DownloadRemoved(this);
400 // We have now been deleted. 420 // We have now been deleted.
401 } 421 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
451 } 471 }
452 472
453 DownloadInterruptReason DownloadItemImpl::GetLastReason() const { 473 DownloadInterruptReason DownloadItemImpl::GetLastReason() const {
454 return last_reason_; 474 return last_reason_;
455 } 475 }
456 476
457 bool DownloadItemImpl::IsPaused() const { 477 bool DownloadItemImpl::IsPaused() const {
458 return is_paused_; 478 return is_paused_;
459 } 479 }
460 480
481 bool DownloadItemImpl::CanResumeInterrupted() const {
482 return GetResumeMode() != RESUME_MODE_INVALID;
483 }
484
461 bool DownloadItemImpl::IsTemporary() const { 485 bool DownloadItemImpl::IsTemporary() const {
462 return is_temporary_; 486 return is_temporary_;
463 } 487 }
464 488
465 // TODO(ahendrickson) -- Move |INTERRUPTED| from |IsCancelled()| to
466 // |IsPartialDownload()|, when resuming interrupted downloads is implemented.
467 bool DownloadItemImpl::IsPartialDownload() const { 489 bool DownloadItemImpl::IsPartialDownload() const {
468 return InternalToExternalState(state_) == IN_PROGRESS; 490 DownloadState state = InternalToExternalState(state_);
491 return (state == IN_PROGRESS) || (state == INTERRUPTED);
469 } 492 }
470 493
471 bool DownloadItemImpl::IsInProgress() const { 494 bool DownloadItemImpl::IsInProgress() const {
472 return InternalToExternalState(state_) == IN_PROGRESS; 495 return InternalToExternalState(state_) == IN_PROGRESS;
473 } 496 }
474 497
475 bool DownloadItemImpl::IsCancelled() const { 498 bool DownloadItemImpl::IsCancelled() const {
476 DownloadState external_state = InternalToExternalState(state_); 499 return InternalToExternalState(state_) == CANCELLED;
477 return external_state == CANCELLED || external_state == INTERRUPTED;
478 } 500 }
479 501
480 bool DownloadItemImpl::IsInterrupted() const { 502 bool DownloadItemImpl::IsInterrupted() const {
481 return InternalToExternalState(state_) == INTERRUPTED; 503 return InternalToExternalState(state_) == INTERRUPTED;
482 } 504 }
483 505
484 bool DownloadItemImpl::IsComplete() const { 506 bool DownloadItemImpl::IsComplete() const {
485 return InternalToExternalState(state_) == COMPLETE; 507 return InternalToExternalState(state_) == COMPLETE;
486 } 508 }
487 509
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
655 } 677 }
656 678
657 bool DownloadItemImpl::CanShowInFolder() { 679 bool DownloadItemImpl::CanShowInFolder() {
658 return state_ != CANCELLED_INTERNAL && !file_externally_removed_; 680 return state_ != CANCELLED_INTERNAL && !file_externally_removed_;
659 } 681 }
660 682
661 bool DownloadItemImpl::CanOpenDownload() { 683 bool DownloadItemImpl::CanOpenDownload() {
662 return !file_externally_removed_; 684 return !file_externally_removed_;
663 } 685 }
664 686
687 bool DownloadItemImpl::CanResumeDownload() const {
688 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
689
690 // Do not allow interrupted downloads to be resumed until the target name
691 // has been determined, and the user has validated any dangerous items.
692 // TODO(rdsmith) -- Add a state indicating that filename determination has
693 // occurred.
694 if (GetTargetFilePath().empty())
695 return false;
696
697 if (GetSafetyState() == DANGEROUS)
698 return false;
699
700 return IsInProgress() || CanResumeInterrupted();
701 }
702
665 bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() { 703 bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() {
666 return delegate_->ShouldOpenFileBasedOnExtension(GetUserVerifiedFilePath()); 704 return delegate_->ShouldOpenFileBasedOnExtension(GetUserVerifiedFilePath());
667 } 705 }
668 706
669 bool DownloadItemImpl::GetOpenWhenComplete() const { 707 bool DownloadItemImpl::GetOpenWhenComplete() const {
670 return open_when_complete_; 708 return open_when_complete_;
671 } 709 }
672 710
673 bool DownloadItemImpl::GetAutoOpened() { 711 bool DownloadItemImpl::GetAutoOpened() {
674 return auto_opened_; 712 return auto_opened_;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 url_list += next_url.spec(); 775 url_list += next_url.spec();
738 } 776 }
739 } 777 }
740 778
741 if (verbose) { 779 if (verbose) {
742 description += base::StringPrintf( 780 description += base::StringPrintf(
743 " total = %" PRId64 781 " total = %" PRId64
744 " received = %" PRId64 782 " received = %" PRId64
745 " reason = %s" 783 " reason = %s"
746 " paused = %c" 784 " paused = %c"
785 " resume_mode = %s"
786 " auto_resume_count = %d"
747 " safety = %s" 787 " safety = %s"
788 " all_data_saved = %c"
748 " last_modified = '%s'" 789 " last_modified = '%s'"
749 " etag = '%s'" 790 " etag = '%s'"
791 " has_download_file = %s"
750 " url_chain = \n\t\"%s\"\n\t" 792 " url_chain = \n\t\"%s\"\n\t"
751 " full_path = \"%" PRFilePath "\"" 793 " full_path = \"%" PRFilePath "\"\n\t"
752 " target_path = \"%" PRFilePath "\"" 794 " target_path = \"%" PRFilePath "\"",
753 " has download file = %s",
754 GetTotalBytes(), 795 GetTotalBytes(),
755 GetReceivedBytes(), 796 GetReceivedBytes(),
756 InterruptReasonDebugString(last_reason_).c_str(), 797 InterruptReasonDebugString(last_reason_).c_str(),
757 IsPaused() ? 'T' : 'F', 798 IsPaused() ? 'T' : 'F',
799 DebugResumeModeString(GetResumeMode()),
800 auto_resume_count_,
758 DebugSafetyStateString(GetSafetyState()), 801 DebugSafetyStateString(GetSafetyState()),
802 AllDataSaved() ? 'T' : 'F',
759 GetLastModifiedTime().c_str(), 803 GetLastModifiedTime().c_str(),
760 GetETag().c_str(), 804 GetETag().c_str(),
805 download_file_.get() ? "true" : "false",
761 url_list.c_str(), 806 url_list.c_str(),
762 GetFullPath().value().c_str(), 807 GetFullPath().value().c_str(),
763 GetTargetFilePath().value().c_str(), 808 GetTargetFilePath().value().c_str());
764 download_file_.get() ? "true" : "false");
765 } else { 809 } else {
766 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); 810 description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
767 } 811 }
768 812
769 description += " }"; 813 description += " }";
770 814
771 return description; 815 return description;
772 } 816 }
773 817
774 void DownloadItemImpl::MockDownloadOpenForTesting() { 818 void DownloadItemImpl::MockDownloadOpenForTesting() {
775 open_enabled_ = false; 819 open_enabled_ = false;
776 } 820 }
777 821
822 DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
823 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
824 if (!IsInterrupted())
825 return RESUME_MODE_INVALID;
826
827 ResumeMode mode = RESUME_MODE_INVALID;
828
829 switch(last_reason_) {
830 case DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
831 case DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
832 mode = RESUME_MODE_IMMEDIATE_CONTINUE; // Continue immediately.
833 break;
834
835 case DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION:
836 case DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
837 case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
838 mode = RESUME_MODE_IMMEDIATE_RESTART; // Restart immediately.
839 break;
840
841 case DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
842 case DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
843 case DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
844 case DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
845 case DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
846 case DOWNLOAD_INTERRUPT_REASON_CRASH:
847 mode = RESUME_MODE_USER_CONTINUE; // Continue via user input.
848 break;
849
850 case DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
851 case DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
852 case DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
853 case DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
854 case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
855 mode = RESUME_MODE_USER_RESTART; // Restart via user input.
856 break;
857
858 case DOWNLOAD_INTERRUPT_REASON_NONE:
859 case DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
860 case DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
861 case DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
862 break;
863
864 case DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
865 case DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
866 break;
867 }
868
869 // Check if we have exhausted the number of automatic retry attempts.
870 if (auto_resume_count_ >= kMaxAutoResumeAttempts) {
871 if (mode == RESUME_MODE_IMMEDIATE_CONTINUE)
872 mode = RESUME_MODE_USER_CONTINUE;
873 else if (mode == RESUME_MODE_IMMEDIATE_RESTART)
874 mode = RESUME_MODE_USER_RESTART;
875 }
876
877 return mode;
878 }
879
880 void DownloadItemImpl::ResumeInterruptedDownload() {
881 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
882
883 // If the flag for downloads resumption isn't enabled, ignore
884 // this request.
885 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
886 if (!command_line.HasSwitch(switches::kEnableDownloadResumption))
887 return;
888
889 // Handle the case of clicking 'Resume' in the download shelf.
890 DCHECK(IsInterrupted());
891
892 DVLOG(20) << __FUNCTION__ << "()" << DebugString(true);
893
894 // If we can't get a web contents, we can't resume the download.
895 // TODO(rdsmith): Find some alternative web contents to use--this
896 // means we can't restart a download if it's a download imported
897 // from the history.
898 if (!GetWebContents())
899 return;
900
901 scoped_ptr<DownloadUrlParameters> download_params(
902 DownloadUrlParameters::FromWebContents(GetWebContents(),
903 GetOriginalUrl()));
904
905 download_params->set_file_path(GetFullPath());
906 download_params->set_offset(GetReceivedBytes());
907 download_params->set_hash_state(GetHashState());
908
909 Referrer referrer(GetReferrerUrl(), WebKit::WebReferrerPolicyDefault);
910 download_params->set_referrer(referrer);
911 download_params->set_last_modified(GetLastModifiedTime());
912 download_params->set_etag(GetETag());
913 download_params->set_callback(DownloadUrlParameters::OnStartedCallback());
914
915 delegate_->ResumeInterruptedDownload(download_params.Pass(), GetGlobalId());
916 }
917
778 void DownloadItemImpl::NotifyRemoved() { 918 void DownloadItemImpl::NotifyRemoved() {
779 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this)); 919 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this));
780 } 920 }
781 921
782 void DownloadItemImpl::OnDownloadedFileRemoved() { 922 void DownloadItemImpl::OnDownloadedFileRemoved() {
783 file_externally_removed_ = true; 923 file_externally_removed_ = true;
784 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true); 924 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
785 UpdateObservers(); 925 UpdateObservers();
786 } 926 }
787 927
788 base::WeakPtr<DownloadDestinationObserver> 928 base::WeakPtr<DownloadDestinationObserver>
789 DownloadItemImpl::DestinationObserverAsWeakPtr() { 929 DownloadItemImpl::DestinationObserverAsWeakPtr() {
790 return weak_ptr_factory_.GetWeakPtr(); 930 return weak_ptr_factory_.GetWeakPtr();
791 } 931 }
792 932
933 const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const {
934 return bound_net_log_;
935 }
936
793 void DownloadItemImpl::SetTotalBytes(int64 total_bytes) { 937 void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
794 total_bytes_ = total_bytes; 938 total_bytes_ = total_bytes;
795 } 939 }
796 940
797 // Updates from the download thread may have been posted while this download 941 // Updates from the download thread may have been posted while this download
798 // was being cancelled in the UI thread, so we'll accept them unless we're 942 // was being cancelled in the UI thread, so we'll accept them unless we're
799 // complete. 943 // complete.
800 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, 944 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far,
801 int64 bytes_per_sec, 945 int64 bytes_per_sec,
802 const std::string& hash_state) { 946 const std::string& hash_state) {
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
939 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data); 1083 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
940 } else { 1084 } else {
941 bound_net_log_.AddEvent( 1085 bound_net_log_.AddEvent(
942 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data); 1086 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data);
943 } 1087 }
944 1088
945 VLOG(20) << __FUNCTION__ << "() " << DebugString(true); 1089 VLOG(20) << __FUNCTION__ << "() " << DebugString(true);
946 } 1090 }
947 1091
948 // We're starting the download. 1092 // We're starting the download.
949 void DownloadItemImpl::Start(scoped_ptr<DownloadFile> file) { 1093 void DownloadItemImpl::Start(
1094 scoped_ptr<DownloadFile> file,
1095 scoped_ptr<DownloadRequestHandleInterface> req_handle) {
1096 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
950 DCHECK(!download_file_.get()); 1097 DCHECK(!download_file_.get());
951 DCHECK(file.get()); 1098 DCHECK(file.get());
1099 DCHECK(req_handle.get());
1100
952 download_file_ = file.Pass(); 1101 download_file_ = file.Pass();
1102 request_handle_ = req_handle.Pass();
1103
1104 TransitionTo(IN_PROGRESS_INTERNAL);
1105
1106 last_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE;
953 1107
954 BrowserThread::PostTask( 1108 BrowserThread::PostTask(
955 BrowserThread::FILE, FROM_HERE, 1109 BrowserThread::FILE, FROM_HERE,
956 base::Bind(&DownloadFile::Initialize, 1110 base::Bind(&DownloadFile::Initialize,
957 // Safe because we control download file lifetime. 1111 // Safe because we control download file lifetime.
958 base::Unretained(download_file_.get()), 1112 base::Unretained(download_file_.get()),
959 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, 1113 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
960 weak_ptr_factory_.GetWeakPtr()))); 1114 weak_ptr_factory_.GetWeakPtr())));
961 } 1115 }
962 1116
963 void DownloadItemImpl::OnDownloadFileInitialized( 1117 void DownloadItemImpl::OnDownloadFileInitialized(
964 DownloadInterruptReason result) { 1118 DownloadInterruptReason result) {
1119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
965 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) { 1120 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
966 Interrupt(result); 1121 Interrupt(result);
967 // TODO(rdsmith): It makes no sense to continue along the 1122 // TODO(rdsmith): It makes no sense to continue along the
968 // regular download path after we've gotten an error. But it's 1123 // regular download path after we've gotten an error. But it's
969 // the way the code has historically worked, and this allows us 1124 // the way the code has historically worked, and this allows us
970 // to get the download persisted and observers of the download manager 1125 // to get the download persisted and observers of the download manager
971 // notified, so tests work. When we execute all side effects of cancel 1126 // notified, so tests work. When we execute all side effects of cancel
972 // (including queue removal) immedately rather than waiting for 1127 // (including queue removal) immediately rather than waiting for
973 // persistence we should replace this comment with a "return;". 1128 // persistence we should replace this comment with a "return;".
974 } 1129 }
975 1130
1131 // If we're resuming an interrupted download, we may already know
1132 // the download target so we can skip target name determination.
1133 if (!GetTargetFilePath().empty()) {
1134 // If we're resuming, we should have completed the rename (and set
1135 // the full path) before accepting the interrupt.
1136 DCHECK(!GetFullPath().empty());
1137 delegate_->ShowDownloadInBrowser(this);
1138 MaybeCompleteDownload();
1139 return;
1140 }
1141
976 delegate_->DetermineDownloadTarget( 1142 delegate_->DetermineDownloadTarget(
977 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined, 1143 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
978 weak_ptr_factory_.GetWeakPtr())); 1144 weak_ptr_factory_.GetWeakPtr()));
979 } 1145 }
980 1146
981 // Called by delegate_ when the download target path has been 1147 // Called by delegate_ when the download target path has been
982 // determined. 1148 // determined.
983 void DownloadItemImpl::OnDownloadTargetDetermined( 1149 void DownloadItemImpl::OnDownloadTargetDetermined(
984 const FilePath& target_path, 1150 const FilePath& target_path,
985 TargetDisposition disposition, 1151 TargetDisposition disposition,
986 DownloadDangerType danger_type, 1152 DownloadDangerType danger_type,
987 const FilePath& intermediate_path) { 1153 const FilePath& intermediate_path) {
988 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
989 1155
990 // If the |target_path| is empty, then we consider this download to be 1156 // If the |target_path| is empty, then we consider this download to be
991 // canceled. 1157 // canceled.
992 if (target_path.empty()) { 1158 if (target_path.empty()) {
993 Cancel(true); 1159 Cancel(true);
994 return; 1160 return;
995 } 1161 }
996 1162
1163 // TODO(rdsmith,asanka): We are ignoring the possibility that the download
1164 // has been interrupted at this point until we finish the intermediate
1165 // rename and set the full path. That's dangerous, because we might race
1166 // with resumption, either manual (because the interrupt is visible to the
1167 // UI) or automatic. If we keep the "ignore an error on download until
ahendrickson 2012/12/27 17:10:27 Need to finish this comment.
Randy Smith (Not in Mondays) 2012/12/27 17:51:00 Whoops; thank you. Done.
1168
997 VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition 1169 VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition
998 << " " << danger_type << " " << DebugString(true); 1170 << " " << danger_type << " " << DebugString(true);
999 1171
1000 target_path_ = target_path; 1172 target_path_ = target_path;
1001 target_disposition_ = disposition; 1173 target_disposition_ = disposition;
1002 SetDangerType(danger_type); 1174 SetDangerType(danger_type);
1003 // TODO(asanka): SetDangerType() doesn't need to send a notification here. 1175 // TODO(asanka): SetDangerType() doesn't need to send a notification here.
1004 1176
1005 // We want the intermediate and target paths to refer to the same directory so 1177 // We want the intermediate and target paths to refer to the same directory so
1006 // that they are both on the same device and subject to same 1178 // that they are both on the same device and subject to same
1007 // space/permission/availability constraints. 1179 // space/permission/availability constraints.
1008 DCHECK(intermediate_path.DirName() == target_path.DirName()); 1180 DCHECK(intermediate_path.DirName() == target_path.DirName());
1009 1181
1010 if (state_ != IN_PROGRESS_INTERNAL) {
1011 // If we've been cancelled or interrupted while the target was being
1012 // determined, continue the cascade with a null name.
1013 // The error doesn't matter as the cause of download stoppage
1014 // will already have been recorded and will be retained, but we use
1015 // whatever was recorded for consistency.
1016 OnDownloadRenamedToIntermediateName(last_reason_, FilePath());
1017 return;
1018 }
1019
1020 // Rename to intermediate name. 1182 // Rename to intermediate name.
1021 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a 1183 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a
1022 // spurious rename when we can just rename to the final 1184 // spurious rename when we can just rename to the final
1023 // filename. Unnecessary renames may cause bugs like 1185 // filename. Unnecessary renames may cause bugs like
1024 // http://crbug.com/74187. 1186 // http://crbug.com/74187.
1025 DCHECK(!is_save_package_download_); 1187 DCHECK(!is_save_package_download_);
1026 DCHECK(download_file_.get()); 1188 DCHECK(download_file_.get());
1027 DownloadFile::RenameCompletionCallback callback = 1189 DownloadFile::RenameCompletionCallback callback =
1028 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, 1190 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName,
1029 weak_ptr_factory_.GetWeakPtr()); 1191 weak_ptr_factory_.GetWeakPtr());
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1086 if (state_ != IN_PROGRESS_INTERNAL) 1248 if (state_ != IN_PROGRESS_INTERNAL)
1087 return; 1249 return;
1088 1250
1089 // Give the delegate a chance to override. 1251 // Give the delegate a chance to override.
1090 delegate_->ReadyForDownloadCompletion( 1252 delegate_->ReadyForDownloadCompletion(
1091 this, base::Bind(&DownloadItemImpl::ReadyForDownloadCompletionDone, 1253 this, base::Bind(&DownloadItemImpl::ReadyForDownloadCompletionDone,
1092 weak_ptr_factory_.GetWeakPtr())); 1254 weak_ptr_factory_.GetWeakPtr()));
1093 } 1255 }
1094 1256
1095 void DownloadItemImpl::ReadyForDownloadCompletionDone() { 1257 void DownloadItemImpl::ReadyForDownloadCompletionDone() {
1258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1259
1096 if (state_ != IN_PROGRESS_INTERNAL) 1260 if (state_ != IN_PROGRESS_INTERNAL)
1097 return; 1261 return;
1098 1262
1099 VLOG(20) << __FUNCTION__ << "()" 1263 VLOG(20) << __FUNCTION__ << "()" << " " << DebugString(true);
1100 << " " << DebugString(true);
1101 DCHECK(!GetTargetFilePath().empty()); 1264 DCHECK(!GetTargetFilePath().empty());
1102 DCHECK_NE(DANGEROUS, GetSafetyState()); 1265 DCHECK_NE(DANGEROUS, GetSafetyState());
1103 1266
1104 // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration. 1267 // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration.
1105 if (is_save_package_download_) { 1268 if (is_save_package_download_) {
1106 // Avoid doing anything on the file thread; there's nothing we control 1269 // Avoid doing anything on the file thread; there's nothing we control
1107 // there. 1270 // there.
1108 // Strictly speaking, this skips giving the embedder a chance to open 1271 // Strictly speaking, this skips giving the embedder a chance to open
1109 // the download. But on a save package download, there's no real 1272 // the download. But on a save package download, there's no real
1110 // concept of opening. 1273 // concept of opening.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1169 if (delegate_->ShouldOpenDownload( 1332 if (delegate_->ShouldOpenDownload(
1170 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened, 1333 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened,
1171 weak_ptr_factory_.GetWeakPtr()))) { 1334 weak_ptr_factory_.GetWeakPtr()))) {
1172 Completed(); 1335 Completed();
1173 } else { 1336 } else {
1174 delegate_delayed_complete_ = true; 1337 delegate_delayed_complete_ = true;
1175 } 1338 }
1176 } 1339 }
1177 1340
1178 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { 1341 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
1342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1343
1179 auto_opened_ = auto_opened; 1344 auto_opened_ = auto_opened;
1180 Completed(); 1345 Completed();
1181 } 1346 }
1182 1347
1183 void DownloadItemImpl::Completed() { 1348 void DownloadItemImpl::Completed() {
1184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1185 1350
1186 VLOG(20) << __FUNCTION__ << "() " << DebugString(false); 1351 VLOG(20) << __FUNCTION__ << "() " << DebugString(false);
1187 1352
1188 DCHECK(all_data_saved_); 1353 DCHECK(all_data_saved_);
(...skipping 14 matching lines...) Expand all
1203 1368
1204 auto_opened_ = true; 1369 auto_opened_ = true;
1205 UpdateObservers(); 1370 UpdateObservers();
1206 } 1371 }
1207 } 1372 }
1208 1373
1209 // **** End of Download progression cascade 1374 // **** End of Download progression cascade
1210 1375
1211 // An error occurred somewhere. 1376 // An error occurred somewhere.
1212 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { 1377 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
1378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1379
1213 // Somewhat counter-intuitively, it is possible for us to receive an 1380 // Somewhat counter-intuitively, it is possible for us to receive an
1214 // interrupt after we've already been interrupted. The generation of 1381 // interrupt after we've already been interrupted. The generation of
1215 // interrupts from the file thread Renames and the generation of 1382 // interrupts from the file thread Renames and the generation of
1216 // interrupts from disk writes go through two different mechanisms (driven 1383 // interrupts from disk writes go through two different mechanisms (driven
1217 // by rename requests from UI thread and by write requests from IO thread, 1384 // by rename requests from UI thread and by write requests from IO thread,
1218 // respectively), and since we choose not to keep state on the File thread, 1385 // respectively), and since we choose not to keep state on the File thread,
1219 // this is the place where the races collide. It's also possible for 1386 // this is the place where the races collide. It's also possible for
1220 // interrupts to race with cancels. 1387 // interrupts to race with cancels.
1221 1388
1222 // Whatever happens, the first one to hit the UI thread wins. 1389 // Whatever happens, the first one to hit the UI thread wins.
1223 if (state_ != IN_PROGRESS_INTERNAL) 1390 if (state_ != IN_PROGRESS_INTERNAL)
1224 return; 1391 return;
1225 1392
1226 last_reason_ = reason; 1393 last_reason_ = reason;
1394
1227 TransitionTo(INTERRUPTED_INTERNAL); 1395 TransitionTo(INTERRUPTED_INTERNAL);
1228 1396
1229 CancelDownloadFile(); 1397 ResumeMode resume_mode = GetResumeMode();
1398 if (resume_mode == RESUME_MODE_IMMEDIATE_RESTART ||
1399 resume_mode == RESUME_MODE_USER_RESTART) {
1400 // Remove the download file; no point in leaving data around we
1401 // aren't going to use.
1402 CancelDownloadFile();
1403 } else {
1404 // Keep the file around and maybe re-use it.
1405 BrowserThread::PostTask(
1406 BrowserThread::FILE, FROM_HERE,
1407 base::Bind(&DownloadFileDetach, base::Passed(&download_file_)));
1408 }
1230 1409
1231 // Cancel the originating URL request. 1410 // Cancel the originating URL request.
1232 request_handle_->CancelRequest(); 1411 request_handle_->CancelRequest();
1233 1412
1234 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); 1413 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
1414 AutoResumeIfValid();
1235 } 1415 }
1236 1416
1237 void DownloadItemImpl::CancelDownloadFile() { 1417 void DownloadItemImpl::CancelDownloadFile() {
1418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1419
1238 // TODO(rdsmith/benjhayden): Remove condition as part of 1420 // TODO(rdsmith/benjhayden): Remove condition as part of
1239 // SavePackage integration. 1421 // |SavePackage| integration.
1240 // download_file_ can be NULL if Interrupt() is called after the download file 1422 // |download_file_| can be NULL if Interrupt() is called after the
1241 // has been released. 1423 // download file has been released.
1242 if (!is_save_package_download_ && download_file_.get()) { 1424 if (!is_save_package_download_ && download_file_.get()) {
1243 BrowserThread::PostTask( 1425 BrowserThread::PostTask(
1244 BrowserThread::FILE, FROM_HERE, 1426 BrowserThread::FILE, FROM_HERE,
1245 // Will be deleted at end of task execution. 1427 // Will be deleted at end of task execution.
1246 base::Bind(&DownloadFileCancel, base::Passed(&download_file_))); 1428 base::Bind(&DownloadFileCancel, base::Passed(&download_file_)));
1247 } 1429 }
1248 } 1430 }
1249 1431
1250 bool DownloadItemImpl::IsDownloadReadyForCompletion() { 1432 bool DownloadItemImpl::IsDownloadReadyForCompletion() {
1251 VLOG(20) << __FUNCTION__ << " " << AllDataSaved() 1433 VLOG(20) << __FUNCTION__ << " " << AllDataSaved()
1252 << " " << (GetSafetyState() != DownloadItem::DANGEROUS) 1434 << " " << (GetSafetyState() != DownloadItem::DANGEROUS)
1253 << " " << (state_ == IN_PROGRESS_INTERNAL) 1435 << " " << (state_ == IN_PROGRESS_INTERNAL)
1254 << " " << !GetTargetFilePath().empty() 1436 << " " << !GetTargetFilePath().empty()
1255 << " " << (target_path_.DirName() == current_path_.DirName()); 1437 << " " << (target_path_.DirName() == current_path_.DirName());
1438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1439
1256 // If we don't have all the data, the download is not ready for 1440 // If we don't have all the data, the download is not ready for
1257 // completion. 1441 // completion.
1258 if (!AllDataSaved()) 1442 if (!AllDataSaved())
1259 return false; 1443 return false;
1260 1444
1261 // If the download is dangerous, but not yet validated, it's not ready for 1445 // If the download is dangerous, but not yet validated, it's not ready for
1262 // completion. 1446 // completion.
1263 if (GetSafetyState() == DownloadItem::DANGEROUS) 1447 if (GetSafetyState() == DownloadItem::DANGEROUS)
1264 return false; 1448 return false;
1265 1449
1266 // If the download isn't active (e.g. has been cancelled) it's not 1450 // If the download isn't active (e.g. has been cancelled) it's not
1267 // ready for completion. 1451 // ready for completion.
1268 if (state_ != IN_PROGRESS_INTERNAL) 1452 if (state_ != IN_PROGRESS_INTERNAL)
1269 return false; 1453 return false;
1270 1454
1271 // If the target filename hasn't been determined, then it's not ready for 1455 // If the target filename hasn't been determined, then it's not ready for
1272 // completion. This is checked in ReadyForDownloadCompletionDone(). 1456 // completion. This is checked in ReadyForDownloadCompletionDone().
1273 if (GetTargetFilePath().empty()) 1457 if (GetTargetFilePath().empty())
1274 return false; 1458 return false;
1275 1459
1276 // This is checked in NeedsRename(). Without this conditional, 1460 // This is checked in NeedsRename(). Without this conditional,
1277 // browser_tests:DownloadTest.DownloadMimeType fails the DCHECK. 1461 // browser_tests:DownloadTest.DownloadMimeType fails the DCHECK.
1278 if (target_path_.DirName() != current_path_.DirName()) 1462 if (target_path_.DirName() != current_path_.DirName())
1279 return false; 1463 return false;
1280 1464
1281 return true; 1465 return true;
1282 } 1466 }
1283 1467
1284 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) { 1468 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
1469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1470
1285 if (state_ == new_state) 1471 if (state_ == new_state)
1286 return; 1472 return;
1287 1473
1288 DownloadInternalState old_state = state_; 1474 DownloadInternalState old_state = state_;
1289 state_ = new_state; 1475 state_ = new_state;
1290 1476
1291 switch (state_) { 1477 switch (state_) {
1292 case COMPLETING_INTERNAL: 1478 case COMPLETING_INTERNAL:
1293 bound_net_log_.AddEvent( 1479 bound_net_log_.AddEvent(
1294 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING, 1480 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING,
1295 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_)); 1481 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_));
1296 break; 1482 break;
1297 case COMPLETE_INTERNAL: 1483 case COMPLETE_INTERNAL:
1298 bound_net_log_.AddEvent( 1484 bound_net_log_.AddEvent(
1299 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED, 1485 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED,
1300 base::Bind(&ItemFinishedNetLogCallback, auto_opened_)); 1486 base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
1301 break; 1487 break;
1302 case INTERRUPTED_INTERNAL: 1488 case INTERRUPTED_INTERNAL:
1303 bound_net_log_.AddEvent( 1489 bound_net_log_.AddEvent(
1304 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED, 1490 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED,
1305 base::Bind(&ItemInterruptedNetLogCallback, last_reason_, 1491 base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
1306 received_bytes_, &hash_state_)); 1492 received_bytes_, &hash_state_));
1307 break; 1493 break;
1494 case IN_PROGRESS_INTERNAL:
1495 if (old_state == INTERRUPTED_INTERNAL) {
1496 bound_net_log_.AddEvent(
1497 net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
1498 base::Bind(&ItemResumingNetLogCallback,
1499 false, last_reason_, received_bytes_, &hash_state_));
1500 }
1501 break;
1308 case CANCELLED_INTERNAL: 1502 case CANCELLED_INTERNAL:
1309 bound_net_log_.AddEvent( 1503 bound_net_log_.AddEvent(
1310 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED, 1504 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
1311 base::Bind(&ItemCanceledNetLogCallback, received_bytes_, 1505 base::Bind(&ItemCanceledNetLogCallback, received_bytes_,
1312 &hash_state_)); 1506 &hash_state_));
1313 break; 1507 break;
1314 default: 1508 default:
1315 break; 1509 break;
1316 } 1510 }
1317 1511
1318 VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true) 1512 VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true)
1319 << " " << InternalToExternalState(old_state) 1513 << " " << InternalToExternalState(old_state)
1320 << " " << InternalToExternalState(state_); 1514 << " " << InternalToExternalState(state_);
1321 1515
1322 // Only update observers on user visible state changes. 1516 // Only update observers on user visible state changes.
1323 if (InternalToExternalState(old_state) != InternalToExternalState(state_)) 1517 if (InternalToExternalState(state_) != InternalToExternalState(old_state))
1324 UpdateObservers(); 1518 UpdateObservers();
1325 1519
1326 bool is_done = (state_ != IN_PROGRESS_INTERNAL && 1520 bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
1327 state_ != COMPLETING_INTERNAL); 1521 state_ != COMPLETING_INTERNAL);
1328 bool was_done = (old_state != IN_PROGRESS_INTERNAL && 1522 bool was_done = (old_state != IN_PROGRESS_INTERNAL &&
1329 old_state != COMPLETING_INTERNAL); 1523 old_state != COMPLETING_INTERNAL);
1524 // Termination
1330 if (is_done && !was_done) 1525 if (is_done && !was_done)
1331 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE); 1526 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
1527
1528 // Resumption
1529 if (was_done && !is_done) {
1530 std::string file_name(target_path_.BaseName().value());
1531 bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE,
1532 base::Bind(&ItemActivatedNetLogCallback,
1533 this, SRC_ACTIVE_DOWNLOAD,
1534 &file_name));
1535 }
1332 } 1536 }
1333 1537
1334 void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) { 1538 void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
1335 danger_type_ = danger_type; 1539 danger_type_ = danger_type;
1336 // Notify observers if the safety state has changed as a result of the new 1540 // Notify observers if the safety state has changed as a result of the new
1337 // danger type. 1541 // danger type.
1338 SafetyState updated_value = IsDangerous() ? 1542 SafetyState updated_value = IsDangerous() ?
1339 DownloadItem::DANGEROUS : DownloadItem::SAFE; 1543 DownloadItem::DANGEROUS : DownloadItem::SAFE;
1340 if (updated_value != safety_state_) { 1544 if (updated_value != safety_state_) {
1341 safety_state_ = updated_value; 1545 safety_state_ = updated_value;
(...skipping 12 matching lines...) Expand all
1354 DCHECK(!new_path.empty()); 1558 DCHECK(!new_path.empty());
1355 1559
1356 bound_net_log_.AddEvent( 1560 bound_net_log_.AddEvent(
1357 net::NetLog::TYPE_DOWNLOAD_ITEM_RENAMED, 1561 net::NetLog::TYPE_DOWNLOAD_ITEM_RENAMED,
1358 base::Bind(&ItemRenamedNetLogCallback, &current_path_, &new_path)); 1562 base::Bind(&ItemRenamedNetLogCallback, &current_path_, &new_path));
1359 1563
1360 current_path_ = new_path; 1564 current_path_ = new_path;
1361 UpdateObservers(); 1565 UpdateObservers();
1362 } 1566 }
1363 1567
1568 void DownloadItemImpl::AutoResumeIfValid() {
1569 DVLOG(20) << __FUNCTION__ << "() " << DebugString(true);
1570 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1571 ResumeMode mode = GetResumeMode();
1572
1573 if ((mode == RESUME_MODE_IMMEDIATE_RESTART) ||
1574 (mode == RESUME_MODE_IMMEDIATE_CONTINUE)) {
1575 if (mode == RESUME_MODE_IMMEDIATE_RESTART) {
ahendrickson 2012/12/27 17:10:27 I know I wrote this, but it might look better if t
Randy Smith (Not in Mondays) 2012/12/27 17:51:00 Rewrote routine; let me know what you think. Note
1576 received_bytes_ = 0; // Restart instead of continuing.
1577 hash_state_ = "";
1578 last_modified_time_ = "";
1579 etag_ = "";
1580 }
1581
1582 auto_resume_count_++;
1583
1584 ResumeInterruptedDownload();
1585 }
1586 }
1587
1364 // static 1588 // static
1365 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( 1589 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
1366 DownloadInternalState internal_state) { 1590 DownloadInternalState internal_state) {
1367 switch (internal_state) { 1591 switch (internal_state) {
1368 case IN_PROGRESS_INTERNAL: 1592 case IN_PROGRESS_INTERNAL:
1369 return IN_PROGRESS; 1593 return IN_PROGRESS;
1370 case COMPLETING_INTERNAL: 1594 case COMPLETING_INTERNAL:
1371 return IN_PROGRESS; 1595 return IN_PROGRESS;
1372 case COMPLETE_INTERNAL: 1596 case COMPLETE_INTERNAL:
1373 return COMPLETE; 1597 return COMPLETE;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1412 case CANCELLED_INTERNAL: 1636 case CANCELLED_INTERNAL:
1413 return "CANCELLED"; 1637 return "CANCELLED";
1414 case INTERRUPTED_INTERNAL: 1638 case INTERRUPTED_INTERNAL:
1415 return "INTERRUPTED"; 1639 return "INTERRUPTED";
1416 default: 1640 default:
1417 NOTREACHED() << "Unknown download state " << state; 1641 NOTREACHED() << "Unknown download state " << state;
1418 return "unknown"; 1642 return "unknown";
1419 }; 1643 };
1420 } 1644 }
1421 1645
1646 const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) {
1647 switch (mode) {
1648 case RESUME_MODE_INVALID:
1649 return "INVALID";
1650 case RESUME_MODE_IMMEDIATE_CONTINUE:
1651 return "IMMEDIATE_CONTINUE";
1652 case RESUME_MODE_IMMEDIATE_RESTART:
1653 return "IMMEDIATE_RESTART";
1654 case RESUME_MODE_USER_CONTINUE:
1655 return "USER_CONTINUE";
1656 case RESUME_MODE_USER_RESTART:
1657 return "USER_RESTART";
1658 default:
1659 NOTREACHED() << "Unknown resume mode " << mode;
1660 return "unknown";
1661 }
1662 }
1663
1422 } // namespace content 1664 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698