OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // 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 Loading... |
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 Loading... |
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 Loading... |
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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 | 340 |
329 request_handle_->PauseRequest(); | 341 request_handle_->PauseRequest(); |
330 is_paused_ = true; | 342 is_paused_ = true; |
331 UpdateObservers(); | 343 UpdateObservers(); |
332 } | 344 } |
333 | 345 |
334 void DownloadItemImpl::Resume() { | 346 void DownloadItemImpl::Resume() { |
335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
336 | 348 |
337 // Ignore irrelevant states. | 349 // Ignore irrelevant states. |
338 if (state_ != IN_PROGRESS_INTERNAL || !is_paused_) | 350 if (state_ == COMPLETE_INTERNAL || state_ == COMPLETING_INTERNAL || |
| 351 !is_paused_) |
339 return; | 352 return; |
340 | 353 |
| 354 if (state_ == INTERRUPTED_INTERNAL) { |
| 355 auto_resume_count_ = 0; // User input resets the counter. |
| 356 ResumeInterruptedDownload(); |
| 357 return; |
| 358 } |
| 359 DCHECK_EQ(IN_PROGRESS_INTERNAL, state_); |
| 360 |
341 request_handle_->ResumeRequest(); | 361 request_handle_->ResumeRequest(); |
342 is_paused_ = false; | 362 is_paused_ = false; |
343 UpdateObservers(); | 363 UpdateObservers(); |
344 } | 364 } |
345 | 365 |
346 void DownloadItemImpl::Cancel(bool user_cancel) { | 366 void DownloadItemImpl::Cancel(bool user_cancel) { |
347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 367 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
348 | 368 |
| 369 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); |
| 370 if (state_ != IN_PROGRESS_INTERNAL && state_ != INTERRUPTED_INTERNAL) { |
| 371 // Small downloads might be complete before this method has |
| 372 // a chance to run. |
| 373 return; |
| 374 } |
| 375 |
349 last_reason_ = user_cancel ? | 376 last_reason_ = user_cancel ? |
350 DOWNLOAD_INTERRUPT_REASON_USER_CANCELED : | 377 DOWNLOAD_INTERRUPT_REASON_USER_CANCELED : |
351 DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN; | 378 DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN; |
352 | 379 |
353 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); | |
354 if (state_ != IN_PROGRESS_INTERNAL) { | |
355 // Small downloads might be complete before this method has | |
356 // a chance to run. | |
357 return; | |
358 } | |
359 | |
360 RecordDownloadCount(CANCELLED_COUNT); | 380 RecordDownloadCount(CANCELLED_COUNT); |
361 | 381 |
362 TransitionTo(CANCELLED_INTERNAL); | 382 TransitionTo(CANCELLED_INTERNAL); |
363 | 383 |
364 CancelDownloadFile(); | 384 CancelDownloadFile(); |
365 | 385 |
366 // Cancel the originating URL request. | 386 // Cancel the originating URL request. |
367 request_handle_->CancelRequest(); | 387 request_handle_->CancelRequest(); |
368 } | 388 } |
369 | 389 |
370 void DownloadItemImpl::Delete(DeleteReason reason) { | 390 void DownloadItemImpl::Delete(DeleteReason reason) { |
| 391 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); |
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
372 | 393 |
373 switch (reason) { | 394 switch (reason) { |
374 case DELETE_DUE_TO_USER_DISCARD: | 395 case DELETE_DUE_TO_USER_DISCARD: |
375 UMA_HISTOGRAM_ENUMERATION( | 396 UMA_HISTOGRAM_ENUMERATION( |
376 "Download.UserDiscard", GetDangerType(), | 397 "Download.UserDiscard", GetDangerType(), |
377 DOWNLOAD_DANGER_TYPE_MAX); | 398 DOWNLOAD_DANGER_TYPE_MAX); |
378 break; | 399 break; |
379 case DELETE_DUE_TO_BROWSER_SHUTDOWN: | 400 case DELETE_DUE_TO_BROWSER_SHUTDOWN: |
380 UMA_HISTOGRAM_ENUMERATION( | 401 UMA_HISTOGRAM_ENUMERATION( |
381 "Download.Discard", GetDangerType(), | 402 "Download.Discard", GetDangerType(), |
382 DOWNLOAD_DANGER_TYPE_MAX); | 403 DOWNLOAD_DANGER_TYPE_MAX); |
383 break; | 404 break; |
384 default: | 405 default: |
385 NOTREACHED(); | 406 NOTREACHED(); |
386 } | 407 } |
387 | 408 |
388 // Delete the file if it exists and is not owned by a DownloadFile object. | 409 // Delete the file if it exists and is not owned by a DownloadFile object. |
389 // (In the latter case the DownloadFile object will delete it on cancel.) | 410 // (In the latter case the DownloadFile object will delete it on cancel.) |
390 if (!current_path_.empty() && download_file_.get() == NULL) { | 411 if (!current_path_.empty() && download_file_.get() == NULL) { |
391 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 412 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
392 base::Bind(&DeleteDownloadedFile, current_path_)); | 413 base::Bind(&DeleteDownloadedFile, current_path_)); |
393 } | 414 } |
394 Remove(); | 415 Remove(); |
395 // We have now been deleted. | 416 // We have now been deleted. |
396 } | 417 } |
397 | 418 |
398 void DownloadItemImpl::Remove() { | 419 void DownloadItemImpl::Remove() { |
| 420 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true); |
399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 421 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
400 | 422 |
401 delegate_->AssertStateConsistent(this); | 423 delegate_->AssertStateConsistent(this); |
402 Cancel(true); | 424 Cancel(true); |
403 delegate_->AssertStateConsistent(this); | 425 delegate_->AssertStateConsistent(this); |
404 | 426 |
405 NotifyRemoved(); | 427 NotifyRemoved(); |
406 delegate_->DownloadRemoved(this); | 428 delegate_->DownloadRemoved(this); |
407 // We have now been deleted. | 429 // We have now been deleted. |
408 } | 430 } |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 } | 484 } |
463 | 485 |
464 bool DownloadItemImpl::IsPaused() const { | 486 bool DownloadItemImpl::IsPaused() const { |
465 return is_paused_; | 487 return is_paused_; |
466 } | 488 } |
467 | 489 |
468 bool DownloadItemImpl::IsTemporary() const { | 490 bool DownloadItemImpl::IsTemporary() const { |
469 return is_temporary_; | 491 return is_temporary_; |
470 } | 492 } |
471 | 493 |
472 // TODO(ahendrickson) -- Move |INTERRUPTED| from |IsCancelled()| to | |
473 // |IsPartialDownload()|, when resuming interrupted downloads is implemented. | |
474 bool DownloadItemImpl::IsPartialDownload() const { | 494 bool DownloadItemImpl::IsPartialDownload() const { |
475 return InternalToExternalState(state_) == IN_PROGRESS; | 495 DownloadState state = InternalToExternalState(state_); |
| 496 return (state == IN_PROGRESS) || (state == INTERRUPTED); |
476 } | 497 } |
477 | 498 |
478 bool DownloadItemImpl::IsInProgress() const { | 499 bool DownloadItemImpl::IsInProgress() const { |
479 return InternalToExternalState(state_) == IN_PROGRESS; | 500 return InternalToExternalState(state_) == IN_PROGRESS; |
480 } | 501 } |
481 | 502 |
482 bool DownloadItemImpl::IsCancelled() const { | 503 bool DownloadItemImpl::IsCancelled() const { |
483 DownloadState external_state = InternalToExternalState(state_); | 504 return InternalToExternalState(state_) == CANCELLED; |
484 return external_state == CANCELLED || external_state == INTERRUPTED; | |
485 } | 505 } |
486 | 506 |
487 bool DownloadItemImpl::IsInterrupted() const { | 507 bool DownloadItemImpl::IsInterrupted() const { |
488 return InternalToExternalState(state_) == INTERRUPTED; | 508 return InternalToExternalState(state_) == INTERRUPTED; |
489 } | 509 } |
490 | 510 |
491 bool DownloadItemImpl::IsComplete() const { | 511 bool DownloadItemImpl::IsComplete() const { |
492 return InternalToExternalState(state_) == COMPLETE; | 512 return InternalToExternalState(state_) == COMPLETE; |
493 } | 513 } |
494 | 514 |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
750 url_list += next_url.spec(); | 770 url_list += next_url.spec(); |
751 } | 771 } |
752 } | 772 } |
753 | 773 |
754 if (verbose) { | 774 if (verbose) { |
755 description += base::StringPrintf( | 775 description += base::StringPrintf( |
756 " total = %" PRId64 | 776 " total = %" PRId64 |
757 " received = %" PRId64 | 777 " received = %" PRId64 |
758 " reason = %s" | 778 " reason = %s" |
759 " paused = %c" | 779 " paused = %c" |
| 780 " resume_mode = %s" |
| 781 " auto_resume_count = %d" |
760 " safety = %s" | 782 " safety = %s" |
| 783 " all_data_saved = %c" |
761 " last_modified = '%s'" | 784 " last_modified = '%s'" |
762 " etag = '%s'" | 785 " etag = '%s'" |
| 786 " has_download_file = %s" |
763 " url_chain = \n\t\"%s\"\n\t" | 787 " url_chain = \n\t\"%s\"\n\t" |
764 " full_path = \"%" PRFilePath "\"" | 788 " full_path = \"%" PRFilePath "\"\n\t" |
765 " target_path = \"%" PRFilePath "\"" | 789 " target_path = \"%" PRFilePath "\"", |
766 " has download file = %s", | |
767 GetTotalBytes(), | 790 GetTotalBytes(), |
768 GetReceivedBytes(), | 791 GetReceivedBytes(), |
769 InterruptReasonDebugString(last_reason_).c_str(), | 792 InterruptReasonDebugString(last_reason_).c_str(), |
770 IsPaused() ? 'T' : 'F', | 793 IsPaused() ? 'T' : 'F', |
| 794 DebugResumeModeString(GetResumeMode()), |
| 795 auto_resume_count_, |
771 DebugSafetyStateString(GetSafetyState()), | 796 DebugSafetyStateString(GetSafetyState()), |
| 797 AllDataSaved() ? 'T' : 'F', |
772 GetLastModifiedTime().c_str(), | 798 GetLastModifiedTime().c_str(), |
773 GetETag().c_str(), | 799 GetETag().c_str(), |
| 800 download_file_.get() ? "true" : "false", |
774 url_list.c_str(), | 801 url_list.c_str(), |
775 GetFullPath().value().c_str(), | 802 GetFullPath().value().c_str(), |
776 GetTargetFilePath().value().c_str(), | 803 GetTargetFilePath().value().c_str()); |
777 download_file_.get() ? "true" : "false"); | |
778 } else { | 804 } else { |
779 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); | 805 description += base::StringPrintf(" url = \"%s\"", url_list.c_str()); |
780 } | 806 } |
781 | 807 |
782 description += " }"; | 808 description += " }"; |
783 | 809 |
784 return description; | 810 return description; |
785 } | 811 } |
786 | 812 |
787 void DownloadItemImpl::MockDownloadOpenForTesting() { | 813 void DownloadItemImpl::MockDownloadOpenForTesting() { |
788 open_enabled_ = false; | 814 open_enabled_ = false; |
789 } | 815 } |
790 | 816 |
| 817 DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const { |
| 818 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 819 if (!IsInterrupted()) |
| 820 return RESUME_MODE_INVALID; |
| 821 |
| 822 // We can't continue without a handle on the intermediate file. |
| 823 const bool force_restart = current_path_.empty(); |
| 824 |
| 825 // We won't auto-restart if we've used up our attempts or the |
| 826 // download has been paused by user action. |
| 827 const bool force_user = |
| 828 (auto_resume_count_ >= kMaxAutoResumeAttempts || is_paused_); |
| 829 |
| 830 ResumeMode mode = RESUME_MODE_INVALID; |
| 831 |
| 832 switch(last_reason_) { |
| 833 case DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR: |
| 834 case DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT: |
| 835 if (force_restart && force_user) |
| 836 mode = RESUME_MODE_USER_RESTART; |
| 837 else if (force_restart) |
| 838 mode = RESUME_MODE_IMMEDIATE_RESTART; |
| 839 else if (force_user) |
| 840 mode = RESUME_MODE_USER_CONTINUE; |
| 841 else |
| 842 mode = RESUME_MODE_IMMEDIATE_CONTINUE; |
| 843 break; |
| 844 |
| 845 case DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION: |
| 846 case DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE: |
| 847 case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT: |
| 848 if (force_user) |
| 849 mode = RESUME_MODE_USER_RESTART; |
| 850 else |
| 851 mode = RESUME_MODE_IMMEDIATE_RESTART; |
| 852 break; |
| 853 |
| 854 case DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED: |
| 855 case DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED: |
| 856 case DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN: |
| 857 case DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED: |
| 858 case DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN: |
| 859 case DOWNLOAD_INTERRUPT_REASON_CRASH: |
| 860 if (force_restart) |
| 861 mode = RESUME_MODE_USER_RESTART; |
| 862 else |
| 863 mode = RESUME_MODE_USER_CONTINUE; |
| 864 break; |
| 865 |
| 866 case DOWNLOAD_INTERRUPT_REASON_FILE_FAILED: |
| 867 case DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED: |
| 868 case DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE: |
| 869 case DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG: |
| 870 case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE: |
| 871 mode = RESUME_MODE_USER_RESTART; |
| 872 break; |
| 873 |
| 874 case DOWNLOAD_INTERRUPT_REASON_NONE: |
| 875 case DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED: |
| 876 case DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT: |
| 877 case DOWNLOAD_INTERRUPT_REASON_USER_CANCELED: |
| 878 case DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED: |
| 879 case DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED: |
| 880 mode = RESUME_MODE_INVALID; |
| 881 break; |
| 882 } |
| 883 |
| 884 return mode; |
| 885 } |
| 886 |
| 887 void DownloadItemImpl::ResumeInterruptedDownload() { |
| 888 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 889 |
| 890 // If the flag for downloads resumption isn't enabled, ignore |
| 891 // this request. |
| 892 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 893 if (!command_line.HasSwitch(switches::kEnableDownloadResumption)) |
| 894 return; |
| 895 |
| 896 // Handle the case of clicking 'Resume' in the download shelf. |
| 897 DCHECK(IsInterrupted()); |
| 898 |
| 899 DVLOG(20) << __FUNCTION__ << "()" << DebugString(true); |
| 900 |
| 901 // If we can't get a web contents, we can't resume the download. |
| 902 // TODO(rdsmith): Find some alternative web contents to use--this |
| 903 // means we can't restart a download if it's a download imported |
| 904 // from the history. |
| 905 if (!GetWebContents()) |
| 906 return; |
| 907 |
| 908 // Reset the appropriate state if restarting. |
| 909 ResumeMode mode = GetResumeMode(); |
| 910 if (mode == RESUME_MODE_IMMEDIATE_RESTART || |
| 911 mode == RESUME_MODE_USER_RESTART) { |
| 912 received_bytes_ = 0; |
| 913 hash_state_ = ""; |
| 914 last_modified_time_ = ""; |
| 915 etag_ = ""; |
| 916 } |
| 917 |
| 918 scoped_ptr<DownloadUrlParameters> download_params( |
| 919 DownloadUrlParameters::FromWebContents(GetWebContents(), |
| 920 GetOriginalUrl())); |
| 921 |
| 922 download_params->set_file_path(GetFullPath()); |
| 923 download_params->set_offset(GetReceivedBytes()); |
| 924 download_params->set_hash_state(GetHashState()); |
| 925 download_params->set_last_modified(GetLastModifiedTime()); |
| 926 download_params->set_etag(GetETag()); |
| 927 |
| 928 delegate_->ResumeInterruptedDownload(download_params.Pass(), GetGlobalId()); |
| 929 |
| 930 // Just in case we were interrupted while paused. |
| 931 is_paused_ = false; |
| 932 } |
| 933 |
791 void DownloadItemImpl::NotifyRemoved() { | 934 void DownloadItemImpl::NotifyRemoved() { |
792 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this)); | 935 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this)); |
793 } | 936 } |
794 | 937 |
795 void DownloadItemImpl::OnDownloadedFileRemoved() { | 938 void DownloadItemImpl::OnDownloadedFileRemoved() { |
796 file_externally_removed_ = true; | 939 file_externally_removed_ = true; |
797 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true); | 940 VLOG(20) << __FUNCTION__ << " download=" << DebugString(true); |
798 UpdateObservers(); | 941 UpdateObservers(); |
799 } | 942 } |
800 | 943 |
801 base::WeakPtr<DownloadDestinationObserver> | 944 base::WeakPtr<DownloadDestinationObserver> |
802 DownloadItemImpl::DestinationObserverAsWeakPtr() { | 945 DownloadItemImpl::DestinationObserverAsWeakPtr() { |
803 return weak_ptr_factory_.GetWeakPtr(); | 946 return weak_ptr_factory_.GetWeakPtr(); |
804 } | 947 } |
805 | 948 |
| 949 const net::BoundNetLog& DownloadItemImpl::GetBoundNetLog() const { |
| 950 return bound_net_log_; |
| 951 } |
| 952 |
806 void DownloadItemImpl::SetTotalBytes(int64 total_bytes) { | 953 void DownloadItemImpl::SetTotalBytes(int64 total_bytes) { |
807 total_bytes_ = total_bytes; | 954 total_bytes_ = total_bytes; |
808 } | 955 } |
809 | 956 |
810 // Updates from the download thread may have been posted while this download | 957 // Updates from the download thread may have been posted while this download |
811 // was being cancelled in the UI thread, so we'll accept them unless we're | 958 // was being cancelled in the UI thread, so we'll accept them unless we're |
812 // complete. | 959 // complete. |
813 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, | 960 void DownloadItemImpl::UpdateProgress(int64 bytes_so_far, |
814 int64 bytes_per_sec, | 961 int64 bytes_per_sec, |
815 const std::string& hash_state) { | 962 const std::string& hash_state) { |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
952 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data); | 1099 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data); |
953 } else { | 1100 } else { |
954 bound_net_log_.AddEvent( | 1101 bound_net_log_.AddEvent( |
955 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data); | 1102 net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, active_data); |
956 } | 1103 } |
957 | 1104 |
958 VLOG(20) << __FUNCTION__ << "() " << DebugString(true); | 1105 VLOG(20) << __FUNCTION__ << "() " << DebugString(true); |
959 } | 1106 } |
960 | 1107 |
961 // We're starting the download. | 1108 // We're starting the download. |
962 void DownloadItemImpl::Start(scoped_ptr<DownloadFile> file) { | 1109 void DownloadItemImpl::Start( |
| 1110 scoped_ptr<DownloadFile> file, |
| 1111 scoped_ptr<DownloadRequestHandleInterface> req_handle) { |
| 1112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
963 DCHECK(!download_file_.get()); | 1113 DCHECK(!download_file_.get()); |
964 DCHECK(file.get()); | 1114 DCHECK(file.get()); |
| 1115 DCHECK(req_handle.get()); |
| 1116 |
965 download_file_ = file.Pass(); | 1117 download_file_ = file.Pass(); |
| 1118 request_handle_ = req_handle.Pass(); |
| 1119 |
| 1120 TransitionTo(IN_PROGRESS_INTERNAL); |
| 1121 |
| 1122 last_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE; |
966 | 1123 |
967 BrowserThread::PostTask( | 1124 BrowserThread::PostTask( |
968 BrowserThread::FILE, FROM_HERE, | 1125 BrowserThread::FILE, FROM_HERE, |
969 base::Bind(&DownloadFile::Initialize, | 1126 base::Bind(&DownloadFile::Initialize, |
970 // Safe because we control download file lifetime. | 1127 // Safe because we control download file lifetime. |
971 base::Unretained(download_file_.get()), | 1128 base::Unretained(download_file_.get()), |
972 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, | 1129 base::Bind(&DownloadItemImpl::OnDownloadFileInitialized, |
973 weak_ptr_factory_.GetWeakPtr()))); | 1130 weak_ptr_factory_.GetWeakPtr()))); |
974 } | 1131 } |
975 | 1132 |
976 void DownloadItemImpl::OnDownloadFileInitialized( | 1133 void DownloadItemImpl::OnDownloadFileInitialized( |
977 DownloadInterruptReason result) { | 1134 DownloadInterruptReason result) { |
| 1135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
978 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) { | 1136 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) { |
979 Interrupt(result); | 1137 Interrupt(result); |
980 // TODO(rdsmith): It makes no sense to continue along the | 1138 // TODO(rdsmith): It makes no sense to continue along the |
981 // regular download path after we've gotten an error. But it's | 1139 // regular download path after we've gotten an error. But it's |
982 // the way the code has historically worked, and this allows us | 1140 // the way the code has historically worked, and this allows us |
983 // to get the download persisted and observers of the download manager | 1141 // to get the download persisted and observers of the download manager |
984 // notified, so tests work. When we execute all side effects of cancel | 1142 // notified, so tests work. When we execute all side effects of cancel |
985 // (including queue removal) immedately rather than waiting for | 1143 // (including queue removal) immediately rather than waiting for |
986 // persistence we should replace this comment with a "return;". | 1144 // persistence we should replace this comment with a "return;". |
987 } | 1145 } |
988 | 1146 |
| 1147 // If we're resuming an interrupted download, we may already know |
| 1148 // the download target so we can skip target name determination. |
| 1149 if (!GetTargetFilePath().empty() && !GetFullPath().empty()) { |
| 1150 delegate_->ShowDownloadInBrowser(this); |
| 1151 MaybeCompleteDownload(); |
| 1152 return; |
| 1153 } |
| 1154 |
| 1155 // The target path might be set and the full path empty if we failed |
| 1156 // the intermediate rename--re-do file name determination in this case. |
| 1157 // TODO(rdsmith,asanka): Clean up this logic. |
| 1158 target_path_ = FilePath(); |
| 1159 |
989 delegate_->DetermineDownloadTarget( | 1160 delegate_->DetermineDownloadTarget( |
990 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined, | 1161 this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined, |
991 weak_ptr_factory_.GetWeakPtr())); | 1162 weak_ptr_factory_.GetWeakPtr())); |
992 } | 1163 } |
993 | 1164 |
994 // Called by delegate_ when the download target path has been | 1165 // Called by delegate_ when the download target path has been |
995 // determined. | 1166 // determined. |
996 void DownloadItemImpl::OnDownloadTargetDetermined( | 1167 void DownloadItemImpl::OnDownloadTargetDetermined( |
997 const FilePath& target_path, | 1168 const FilePath& target_path, |
998 TargetDisposition disposition, | 1169 TargetDisposition disposition, |
999 DownloadDangerType danger_type, | 1170 DownloadDangerType danger_type, |
1000 const FilePath& intermediate_path) { | 1171 const FilePath& intermediate_path) { |
1001 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1002 | 1173 |
1003 // If the |target_path| is empty, then we consider this download to be | 1174 // If the |target_path| is empty, then we consider this download to be |
1004 // canceled. | 1175 // canceled. |
1005 if (target_path.empty()) { | 1176 if (target_path.empty()) { |
1006 Cancel(true); | 1177 Cancel(true); |
1007 return; | 1178 return; |
1008 } | 1179 } |
1009 | 1180 |
| 1181 // TODO(rdsmith,asanka): We are ignoring the possibility that the download |
| 1182 // has been interrupted at this point until we finish the intermediate |
| 1183 // rename and set the full path. That's dangerous, because we might race |
| 1184 // with resumption, either manual (because the interrupt is visible to the |
| 1185 // UI) or automatic. If we keep the "ignore an error on download until file |
| 1186 // name determination complete" semantics, we need to make sure that the |
| 1187 // error is kept completely invisible until that point. |
| 1188 |
1010 VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition | 1189 VLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition |
1011 << " " << danger_type << " " << DebugString(true); | 1190 << " " << danger_type << " " << DebugString(true); |
1012 | 1191 |
1013 target_path_ = target_path; | 1192 target_path_ = target_path; |
1014 target_disposition_ = disposition; | 1193 target_disposition_ = disposition; |
1015 SetDangerType(danger_type); | 1194 SetDangerType(danger_type); |
1016 // TODO(asanka): SetDangerType() doesn't need to send a notification here. | 1195 // TODO(asanka): SetDangerType() doesn't need to send a notification here. |
1017 | 1196 |
1018 // We want the intermediate and target paths to refer to the same directory so | 1197 // We want the intermediate and target paths to refer to the same directory so |
1019 // that they are both on the same device and subject to same | 1198 // that they are both on the same device and subject to same |
1020 // space/permission/availability constraints. | 1199 // space/permission/availability constraints. |
1021 DCHECK(intermediate_path.DirName() == target_path.DirName()); | 1200 DCHECK(intermediate_path.DirName() == target_path.DirName()); |
1022 | 1201 |
1023 if (state_ != IN_PROGRESS_INTERNAL) { | |
1024 // If we've been cancelled or interrupted while the target was being | |
1025 // determined, continue the cascade with a null name. | |
1026 // The error doesn't matter as the cause of download stoppage | |
1027 // will already have been recorded and will be retained, but we use | |
1028 // whatever was recorded for consistency. | |
1029 OnDownloadRenamedToIntermediateName(last_reason_, FilePath()); | |
1030 return; | |
1031 } | |
1032 | |
1033 // Rename to intermediate name. | 1202 // Rename to intermediate name. |
1034 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a | 1203 // TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a |
1035 // spurious rename when we can just rename to the final | 1204 // spurious rename when we can just rename to the final |
1036 // filename. Unnecessary renames may cause bugs like | 1205 // filename. Unnecessary renames may cause bugs like |
1037 // http://crbug.com/74187. | 1206 // http://crbug.com/74187. |
1038 DCHECK(!is_save_package_download_); | 1207 DCHECK(!is_save_package_download_); |
1039 DCHECK(download_file_.get()); | 1208 DCHECK(download_file_.get()); |
1040 DownloadFile::RenameCompletionCallback callback = | 1209 DownloadFile::RenameCompletionCallback callback = |
1041 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, | 1210 base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName, |
1042 weak_ptr_factory_.GetWeakPtr()); | 1211 weak_ptr_factory_.GetWeakPtr()); |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1174 if (delegate_->ShouldOpenDownload( | 1343 if (delegate_->ShouldOpenDownload( |
1175 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened, | 1344 this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened, |
1176 weak_ptr_factory_.GetWeakPtr()))) { | 1345 weak_ptr_factory_.GetWeakPtr()))) { |
1177 Completed(); | 1346 Completed(); |
1178 } else { | 1347 } else { |
1179 delegate_delayed_complete_ = true; | 1348 delegate_delayed_complete_ = true; |
1180 } | 1349 } |
1181 } | 1350 } |
1182 | 1351 |
1183 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { | 1352 void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) { |
| 1353 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1354 |
1184 auto_opened_ = auto_opened; | 1355 auto_opened_ = auto_opened; |
1185 Completed(); | 1356 Completed(); |
1186 } | 1357 } |
1187 | 1358 |
1188 void DownloadItemImpl::Completed() { | 1359 void DownloadItemImpl::Completed() { |
1189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1190 | 1361 |
1191 VLOG(20) << __FUNCTION__ << "() " << DebugString(false); | 1362 VLOG(20) << __FUNCTION__ << "() " << DebugString(false); |
1192 | 1363 |
1193 DCHECK(all_data_saved_); | 1364 DCHECK(all_data_saved_); |
(...skipping 14 matching lines...) Expand all Loading... |
1208 | 1379 |
1209 auto_opened_ = true; | 1380 auto_opened_ = true; |
1210 UpdateObservers(); | 1381 UpdateObservers(); |
1211 } | 1382 } |
1212 } | 1383 } |
1213 | 1384 |
1214 // **** End of Download progression cascade | 1385 // **** End of Download progression cascade |
1215 | 1386 |
1216 // An error occurred somewhere. | 1387 // An error occurred somewhere. |
1217 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { | 1388 void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { |
| 1389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1390 |
1218 // Somewhat counter-intuitively, it is possible for us to receive an | 1391 // Somewhat counter-intuitively, it is possible for us to receive an |
1219 // interrupt after we've already been interrupted. The generation of | 1392 // interrupt after we've already been interrupted. The generation of |
1220 // interrupts from the file thread Renames and the generation of | 1393 // interrupts from the file thread Renames and the generation of |
1221 // interrupts from disk writes go through two different mechanisms (driven | 1394 // interrupts from disk writes go through two different mechanisms (driven |
1222 // by rename requests from UI thread and by write requests from IO thread, | 1395 // by rename requests from UI thread and by write requests from IO thread, |
1223 // respectively), and since we choose not to keep state on the File thread, | 1396 // respectively), and since we choose not to keep state on the File thread, |
1224 // this is the place where the races collide. It's also possible for | 1397 // this is the place where the races collide. It's also possible for |
1225 // interrupts to race with cancels. | 1398 // interrupts to race with cancels. |
1226 | 1399 |
1227 // Whatever happens, the first one to hit the UI thread wins. | 1400 // Whatever happens, the first one to hit the UI thread wins. |
1228 if (state_ != IN_PROGRESS_INTERNAL) | 1401 if (state_ != IN_PROGRESS_INTERNAL) |
1229 return; | 1402 return; |
1230 | 1403 |
1231 last_reason_ = reason; | 1404 last_reason_ = reason; |
| 1405 |
1232 TransitionTo(INTERRUPTED_INTERNAL); | 1406 TransitionTo(INTERRUPTED_INTERNAL); |
1233 | 1407 |
1234 CancelDownloadFile(); | 1408 ResumeMode resume_mode = GetResumeMode(); |
| 1409 if (resume_mode == RESUME_MODE_IMMEDIATE_RESTART || |
| 1410 resume_mode == RESUME_MODE_USER_RESTART) { |
| 1411 // Remove the download file; no point in leaving data around we |
| 1412 // aren't going to use. |
| 1413 CancelDownloadFile(); |
| 1414 } else { |
| 1415 // Keep the file around and maybe re-use it. |
| 1416 BrowserThread::PostTask( |
| 1417 BrowserThread::FILE, FROM_HERE, |
| 1418 base::Bind(&DownloadFileDetach, base::Passed(&download_file_))); |
| 1419 } |
1235 | 1420 |
1236 // Cancel the originating URL request. | 1421 // Cancel the originating URL request. |
1237 request_handle_->CancelRequest(); | 1422 request_handle_->CancelRequest(); |
1238 | 1423 |
1239 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); | 1424 RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); |
| 1425 AutoResumeIfValid(); |
1240 } | 1426 } |
1241 | 1427 |
1242 void DownloadItemImpl::CancelDownloadFile() { | 1428 void DownloadItemImpl::CancelDownloadFile() { |
| 1429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1430 |
1243 // TODO(rdsmith/benjhayden): Remove condition as part of | 1431 // TODO(rdsmith/benjhayden): Remove condition as part of |
1244 // SavePackage integration. | 1432 // |SavePackage| integration. |
1245 // download_file_ can be NULL if Interrupt() is called after the download file | 1433 // |download_file_| can be NULL if Interrupt() is called after the |
1246 // has been released. | 1434 // download file has been released. |
1247 if (!is_save_package_download_ && download_file_.get()) { | 1435 if (!is_save_package_download_ && download_file_.get()) { |
1248 BrowserThread::PostTask( | 1436 BrowserThread::PostTask( |
1249 BrowserThread::FILE, FROM_HERE, | 1437 BrowserThread::FILE, FROM_HERE, |
1250 // Will be deleted at end of task execution. | 1438 // Will be deleted at end of task execution. |
1251 base::Bind(&DownloadFileCancel, base::Passed(&download_file_))); | 1439 base::Bind(&DownloadFileCancel, base::Passed(&download_file_))); |
1252 } | 1440 } |
1253 } | 1441 } |
1254 | 1442 |
1255 bool DownloadItemImpl::IsDownloadReadyForCompletion( | 1443 bool DownloadItemImpl::IsDownloadReadyForCompletion( |
1256 const base::Closure& state_change_notification) { | 1444 const base::Closure& state_change_notification) { |
(...skipping 24 matching lines...) Expand all Loading... |
1281 | 1469 |
1282 // Give the delegate a chance to hold up a stop sign. It'll call | 1470 // Give the delegate a chance to hold up a stop sign. It'll call |
1283 // use back through the passed callback if it does and that state changes. | 1471 // use back through the passed callback if it does and that state changes. |
1284 if (!delegate_->ShouldCompleteDownload(this, state_change_notification)) | 1472 if (!delegate_->ShouldCompleteDownload(this, state_change_notification)) |
1285 return false; | 1473 return false; |
1286 | 1474 |
1287 return true; | 1475 return true; |
1288 } | 1476 } |
1289 | 1477 |
1290 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) { | 1478 void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) { |
| 1479 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1480 |
1291 if (state_ == new_state) | 1481 if (state_ == new_state) |
1292 return; | 1482 return; |
1293 | 1483 |
1294 DownloadInternalState old_state = state_; | 1484 DownloadInternalState old_state = state_; |
1295 state_ = new_state; | 1485 state_ = new_state; |
1296 | 1486 |
1297 switch (state_) { | 1487 switch (state_) { |
1298 case COMPLETING_INTERNAL: | 1488 case COMPLETING_INTERNAL: |
1299 bound_net_log_.AddEvent( | 1489 bound_net_log_.AddEvent( |
1300 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING, | 1490 net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING, |
1301 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_)); | 1491 base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_)); |
1302 break; | 1492 break; |
1303 case COMPLETE_INTERNAL: | 1493 case COMPLETE_INTERNAL: |
1304 bound_net_log_.AddEvent( | 1494 bound_net_log_.AddEvent( |
1305 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED, | 1495 net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED, |
1306 base::Bind(&ItemFinishedNetLogCallback, auto_opened_)); | 1496 base::Bind(&ItemFinishedNetLogCallback, auto_opened_)); |
1307 break; | 1497 break; |
1308 case INTERRUPTED_INTERNAL: | 1498 case INTERRUPTED_INTERNAL: |
1309 bound_net_log_.AddEvent( | 1499 bound_net_log_.AddEvent( |
1310 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED, | 1500 net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED, |
1311 base::Bind(&ItemInterruptedNetLogCallback, last_reason_, | 1501 base::Bind(&ItemInterruptedNetLogCallback, last_reason_, |
1312 received_bytes_, &hash_state_)); | 1502 received_bytes_, &hash_state_)); |
1313 break; | 1503 break; |
| 1504 case IN_PROGRESS_INTERNAL: |
| 1505 if (old_state == INTERRUPTED_INTERNAL) { |
| 1506 bound_net_log_.AddEvent( |
| 1507 net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED, |
| 1508 base::Bind(&ItemResumingNetLogCallback, |
| 1509 false, last_reason_, received_bytes_, &hash_state_)); |
| 1510 } |
| 1511 break; |
1314 case CANCELLED_INTERNAL: | 1512 case CANCELLED_INTERNAL: |
1315 bound_net_log_.AddEvent( | 1513 bound_net_log_.AddEvent( |
1316 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED, | 1514 net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED, |
1317 base::Bind(&ItemCanceledNetLogCallback, received_bytes_, | 1515 base::Bind(&ItemCanceledNetLogCallback, received_bytes_, |
1318 &hash_state_)); | 1516 &hash_state_)); |
1319 break; | 1517 break; |
1320 default: | 1518 default: |
1321 break; | 1519 break; |
1322 } | 1520 } |
1323 | 1521 |
1324 VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true) | 1522 VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true) |
1325 << " " << InternalToExternalState(old_state) | 1523 << " " << InternalToExternalState(old_state) |
1326 << " " << InternalToExternalState(state_); | 1524 << " " << InternalToExternalState(state_); |
1327 | 1525 |
1328 // Only update observers on user visible state changes. | 1526 // Only update observers on user visible state changes. |
1329 if (InternalToExternalState(old_state) != InternalToExternalState(state_)) | 1527 if (InternalToExternalState(state_) != InternalToExternalState(old_state)) |
1330 UpdateObservers(); | 1528 UpdateObservers(); |
1331 | 1529 |
1332 bool is_done = (state_ != IN_PROGRESS_INTERNAL && | 1530 bool is_done = (state_ != IN_PROGRESS_INTERNAL && |
1333 state_ != COMPLETING_INTERNAL); | 1531 state_ != COMPLETING_INTERNAL); |
1334 bool was_done = (old_state != IN_PROGRESS_INTERNAL && | 1532 bool was_done = (old_state != IN_PROGRESS_INTERNAL && |
1335 old_state != COMPLETING_INTERNAL); | 1533 old_state != COMPLETING_INTERNAL); |
| 1534 // Termination |
1336 if (is_done && !was_done) | 1535 if (is_done && !was_done) |
1337 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE); | 1536 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE); |
| 1537 |
| 1538 // Resumption |
| 1539 if (was_done && !is_done) { |
| 1540 std::string file_name(target_path_.BaseName().AsUTF8Unsafe()); |
| 1541 bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE, |
| 1542 base::Bind(&ItemActivatedNetLogCallback, |
| 1543 this, SRC_ACTIVE_DOWNLOAD, |
| 1544 &file_name)); |
| 1545 } |
1338 } | 1546 } |
1339 | 1547 |
1340 void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) { | 1548 void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) { |
1341 danger_type_ = danger_type; | 1549 danger_type_ = danger_type; |
1342 // Notify observers if the safety state has changed as a result of the new | 1550 // Notify observers if the safety state has changed as a result of the new |
1343 // danger type. | 1551 // danger type. |
1344 SafetyState updated_value = IsDangerous() ? | 1552 SafetyState updated_value = IsDangerous() ? |
1345 DownloadItem::DANGEROUS : DownloadItem::SAFE; | 1553 DownloadItem::DANGEROUS : DownloadItem::SAFE; |
1346 if (updated_value != safety_state_) { | 1554 if (updated_value != safety_state_) { |
1347 safety_state_ = updated_value; | 1555 safety_state_ = updated_value; |
(...skipping 12 matching lines...) Expand all Loading... |
1360 DCHECK(!new_path.empty()); | 1568 DCHECK(!new_path.empty()); |
1361 | 1569 |
1362 bound_net_log_.AddEvent( | 1570 bound_net_log_.AddEvent( |
1363 net::NetLog::TYPE_DOWNLOAD_ITEM_RENAMED, | 1571 net::NetLog::TYPE_DOWNLOAD_ITEM_RENAMED, |
1364 base::Bind(&ItemRenamedNetLogCallback, ¤t_path_, &new_path)); | 1572 base::Bind(&ItemRenamedNetLogCallback, ¤t_path_, &new_path)); |
1365 | 1573 |
1366 current_path_ = new_path; | 1574 current_path_ = new_path; |
1367 UpdateObservers(); | 1575 UpdateObservers(); |
1368 } | 1576 } |
1369 | 1577 |
| 1578 void DownloadItemImpl::AutoResumeIfValid() { |
| 1579 DVLOG(20) << __FUNCTION__ << "() " << DebugString(true); |
| 1580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1581 ResumeMode mode = GetResumeMode(); |
| 1582 |
| 1583 if (mode != RESUME_MODE_IMMEDIATE_RESTART && |
| 1584 mode != RESUME_MODE_IMMEDIATE_CONTINUE) { |
| 1585 return; |
| 1586 } |
| 1587 |
| 1588 auto_resume_count_++; |
| 1589 |
| 1590 ResumeInterruptedDownload(); |
| 1591 } |
| 1592 |
1370 // static | 1593 // static |
1371 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( | 1594 DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState( |
1372 DownloadInternalState internal_state) { | 1595 DownloadInternalState internal_state) { |
1373 switch (internal_state) { | 1596 switch (internal_state) { |
1374 case IN_PROGRESS_INTERNAL: | 1597 case IN_PROGRESS_INTERNAL: |
1375 return IN_PROGRESS; | 1598 return IN_PROGRESS; |
1376 case COMPLETING_INTERNAL: | 1599 case COMPLETING_INTERNAL: |
1377 return IN_PROGRESS; | 1600 return IN_PROGRESS; |
1378 case COMPLETE_INTERNAL: | 1601 case COMPLETE_INTERNAL: |
1379 return COMPLETE; | 1602 return COMPLETE; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1418 case CANCELLED_INTERNAL: | 1641 case CANCELLED_INTERNAL: |
1419 return "CANCELLED"; | 1642 return "CANCELLED"; |
1420 case INTERRUPTED_INTERNAL: | 1643 case INTERRUPTED_INTERNAL: |
1421 return "INTERRUPTED"; | 1644 return "INTERRUPTED"; |
1422 default: | 1645 default: |
1423 NOTREACHED() << "Unknown download state " << state; | 1646 NOTREACHED() << "Unknown download state " << state; |
1424 return "unknown"; | 1647 return "unknown"; |
1425 }; | 1648 }; |
1426 } | 1649 } |
1427 | 1650 |
| 1651 const char* DownloadItemImpl::DebugResumeModeString(ResumeMode mode) { |
| 1652 switch (mode) { |
| 1653 case RESUME_MODE_INVALID: |
| 1654 return "INVALID"; |
| 1655 case RESUME_MODE_IMMEDIATE_CONTINUE: |
| 1656 return "IMMEDIATE_CONTINUE"; |
| 1657 case RESUME_MODE_IMMEDIATE_RESTART: |
| 1658 return "IMMEDIATE_RESTART"; |
| 1659 case RESUME_MODE_USER_CONTINUE: |
| 1660 return "USER_CONTINUE"; |
| 1661 case RESUME_MODE_USER_RESTART: |
| 1662 return "USER_RESTART"; |
| 1663 } |
| 1664 NOTREACHED() << "Unknown resume mode " << mode; |
| 1665 return "unknown"; |
| 1666 } |
| 1667 |
1428 } // namespace content | 1668 } // namespace content |
OLD | NEW |