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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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, ¤t_path_, &new_path)); | 1562 base::Bind(&ItemRenamedNetLogCallback, ¤t_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 Loading... | |
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 |
OLD | NEW |