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

Side by Side Diff: chrome/browser/download/download_item.cc

Issue 7618048: Move the core download files to content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/download/download_item.h"
6
7 #include "base/basictypes.h"
8 #include "base/file_util.h"
9 #include "base/format_macros.h"
10 #include "base/i18n/case_conversion.h"
11 #include "base/logging.h"
12 #include "base/metrics/histogram.h"
13 #include "base/stringprintf.h"
14 #include "base/timer.h"
15 #include "base/utf_string_conversions.h"
16 #include "net/base/net_util.h"
17 #include "chrome/browser/download/download_create_info.h"
18 #include "chrome/browser/download/download_crx_util.h"
19 #include "chrome/browser/download/download_extensions.h"
20 #include "chrome/browser/download/download_file_manager.h"
21 #include "chrome/browser/download/download_history.h"
22 #include "chrome/browser/download/download_manager.h"
23 #include "chrome/browser/download/download_manager_delegate.h"
24 #include "chrome/browser/download/download_prefs.h"
25 #include "chrome/browser/download/download_state_info.h"
26 #include "chrome/browser/download/download_util.h"
27 #include "chrome/browser/extensions/crx_installer.h"
28 #include "chrome/browser/history/download_history_info.h"
29 #include "chrome/browser/platform_util.h"
30 #include "chrome/browser/prefs/pref_service.h"
31 #include "chrome/browser/profiles/profile.h"
32 #include "chrome/common/chrome_notification_types.h"
33 #include "chrome/common/extensions/extension.h"
34 #include "chrome/common/pref_names.h"
35 #include "content/browser/browser_thread.h"
36 #include "content/common/notification_source.h"
37 #include "ui/base/l10n/l10n_util.h"
38
39 // A DownloadItem normally goes through the following states:
40 // * Created (when download starts)
41 // * Made visible to consumers (e.g. Javascript) after the
42 // destination file has been determined.
43 // * Entered into the history database.
44 // * Made visible in the download shelf.
45 // * All data is saved. Note that the actual data download occurs
46 // in parallel with the above steps, but until those steps are
47 // complete, completion of the data download will be ignored.
48 // * Download file is renamed to its final name, and possibly
49 // auto-opened.
50 // TODO(rdsmith): This progress should be reflected in
51 // DownloadItem::DownloadState and a state transition table/state diagram.
52 //
53 // TODO(rdsmith): This description should be updated to reflect the cancel
54 // pathways.
55
56 namespace {
57
58 // Update frequency (milliseconds).
59 const int kUpdateTimeMs = 1000;
60
61 static void DeleteDownloadedFile(const FilePath& path) {
62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
63
64 // Make sure we only delete files.
65 if (!file_util::DirectoryExists(path))
66 file_util::Delete(path, false);
67 }
68
69 const char* DebugSafetyStateString(DownloadItem::SafetyState state) {
70 switch (state) {
71 case DownloadItem::SAFE:
72 return "SAFE";
73 case DownloadItem::DANGEROUS:
74 return "DANGEROUS";
75 case DownloadItem::DANGEROUS_BUT_VALIDATED:
76 return "DANGEROUS_BUT_VALIDATED";
77 default:
78 NOTREACHED() << "Unknown safety state " << state;
79 return "unknown";
80 };
81 }
82
83 const char* DebugDownloadStateString(DownloadItem::DownloadState state) {
84 switch (state) {
85 case DownloadItem::IN_PROGRESS:
86 return "IN_PROGRESS";
87 case DownloadItem::COMPLETE:
88 return "COMPLETE";
89 case DownloadItem::CANCELLED:
90 return "CANCELLED";
91 case DownloadItem::REMOVING:
92 return "REMOVING";
93 case DownloadItem::INTERRUPTED:
94 return "INTERRUPTED";
95 default:
96 NOTREACHED() << "Unknown download state " << state;
97 return "unknown";
98 };
99 }
100
101 DownloadItem::SafetyState GetSafetyState(bool dangerous_file,
102 bool dangerous_url) {
103 return (dangerous_url || dangerous_file) ?
104 DownloadItem::DANGEROUS : DownloadItem::SAFE;
105 }
106
107 // Note: When a download has both |dangerous_file| and |dangerous_url| set,
108 // danger type is set to DANGEROUS_URL since the risk of dangerous URL
109 // overweights that of dangerous file type.
110 DownloadItem::DangerType GetDangerType(bool dangerous_file,
111 bool dangerous_url) {
112 if (dangerous_url) {
113 // dangerous URL overweights dangerous file. We check dangerous URL first.
114 return DownloadItem::DANGEROUS_URL;
115 }
116 return dangerous_file ?
117 DownloadItem::DANGEROUS_FILE : DownloadItem::NOT_DANGEROUS;
118 }
119
120 } // namespace
121
122 // Constructor for reading from the history service.
123 DownloadItem::DownloadItem(DownloadManager* download_manager,
124 const DownloadHistoryInfo& info)
125 : download_id_(-1),
126 full_path_(info.path),
127 url_chain_(1, info.url),
128 referrer_url_(info.referrer_url),
129 total_bytes_(info.total_bytes),
130 received_bytes_(info.received_bytes),
131 start_tick_(base::TimeTicks()),
132 state_(static_cast<DownloadState>(info.state)),
133 start_time_(info.start_time),
134 db_handle_(info.db_handle),
135 download_manager_(download_manager),
136 is_paused_(false),
137 open_when_complete_(false),
138 file_externally_removed_(false),
139 safety_state_(SAFE),
140 auto_opened_(false),
141 is_otr_(false),
142 is_temporary_(false),
143 all_data_saved_(false),
144 opened_(false),
145 open_enabled_(true) {
146 if (IsInProgress())
147 state_ = CANCELLED;
148 if (IsComplete())
149 all_data_saved_ = true;
150 Init(false /* not actively downloading */);
151 }
152
153 // Constructing for a regular download:
154 DownloadItem::DownloadItem(DownloadManager* download_manager,
155 const DownloadCreateInfo& info,
156 bool is_otr)
157 : state_info_(info.original_name, info.save_info.file_path,
158 info.has_user_gesture, info.prompt_user_for_save_location,
159 info.path_uniquifier, false, false,
160 info.is_extension_install),
161 request_handle_(info.request_handle),
162 download_id_(info.download_id),
163 full_path_(info.path),
164 url_chain_(info.url_chain),
165 referrer_url_(info.referrer_url),
166 suggested_filename_(UTF16ToUTF8(info.save_info.suggested_name)),
167 content_disposition_(info.content_disposition),
168 mime_type_(info.mime_type),
169 original_mime_type_(info.original_mime_type),
170 referrer_charset_(info.referrer_charset),
171 total_bytes_(info.total_bytes),
172 received_bytes_(0),
173 last_os_error_(0),
174 start_tick_(base::TimeTicks::Now()),
175 state_(IN_PROGRESS),
176 start_time_(info.start_time),
177 db_handle_(DownloadHistory::kUninitializedHandle),
178 download_manager_(download_manager),
179 is_paused_(false),
180 open_when_complete_(false),
181 file_externally_removed_(false),
182 safety_state_(SAFE),
183 auto_opened_(false),
184 is_otr_(is_otr),
185 is_temporary_(!info.save_info.file_path.empty()),
186 all_data_saved_(false),
187 opened_(false),
188 open_enabled_(true) {
189 Init(true /* actively downloading */);
190 }
191
192 // Constructing for the "Save Page As..." feature:
193 DownloadItem::DownloadItem(DownloadManager* download_manager,
194 const FilePath& path,
195 const GURL& url,
196 bool is_otr)
197 : download_id_(download_manager->GetNextSavePageId()),
198 full_path_(path),
199 url_chain_(1, url),
200 referrer_url_(GURL()),
201 total_bytes_(0),
202 received_bytes_(0),
203 last_os_error_(0),
204 start_tick_(base::TimeTicks::Now()),
205 state_(IN_PROGRESS),
206 start_time_(base::Time::Now()),
207 db_handle_(DownloadHistory::kUninitializedHandle),
208 download_manager_(download_manager),
209 is_paused_(false),
210 open_when_complete_(false),
211 file_externally_removed_(false),
212 safety_state_(SAFE),
213 auto_opened_(false),
214 is_otr_(is_otr),
215 is_temporary_(false),
216 all_data_saved_(false),
217 opened_(false),
218 open_enabled_(true) {
219 Init(true /* actively downloading */);
220 }
221
222 DownloadItem::~DownloadItem() {
223 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
224 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
225
226 TransitionTo(REMOVING);
227 download_manager_->AssertQueueStateConsistent(this);
228 }
229
230 void DownloadItem::AddObserver(Observer* observer) {
231 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
232 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
233
234 observers_.AddObserver(observer);
235 }
236
237 void DownloadItem::RemoveObserver(Observer* observer) {
238 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
239 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
240
241 observers_.RemoveObserver(observer);
242 }
243
244 void DownloadItem::UpdateObservers() {
245 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
246 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
247
248 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
249 }
250
251 bool DownloadItem::CanShowInFolder() {
252 return !IsCancelled() && !file_externally_removed_;
253 }
254
255 bool DownloadItem::CanOpenDownload() {
256 return !Extension::IsExtension(state_info_.target_name) &&
257 !file_externally_removed_;
258 }
259
260 bool DownloadItem::ShouldOpenFileBasedOnExtension() {
261 return download_manager_->delegate()->ShouldOpenFileBasedOnExtension(
262 GetUserVerifiedFilePath());
263 }
264
265 void DownloadItem::OpenFilesBasedOnExtension(bool open) {
266 DownloadPrefs* prefs = download_manager_->download_prefs();
267 if (open)
268 prefs->EnableAutoOpenBasedOnExtension(GetUserVerifiedFilePath());
269 else
270 prefs->DisableAutoOpenBasedOnExtension(GetUserVerifiedFilePath());
271 }
272
273 void DownloadItem::OpenDownload() {
274 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
275 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
276
277 if (IsPartialDownload()) {
278 open_when_complete_ = !open_when_complete_;
279 } else if (IsComplete() && !file_externally_removed_) {
280 // Ideally, we want to detect errors in opening and report them, but we
281 // don't generally have the proper interface for that to the external
282 // program that opens the file. So instead we spawn a check to update
283 // the UI if the file has been deleted in parallel with the open.
284 download_manager_->CheckForFileRemoval(this);
285 opened_ = true;
286 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this));
287
288 // For testing: If download opening is disabled on this item,
289 // make the rest of the routine a no-op.
290 if (!open_enabled_)
291 return;
292
293 if (is_extension_install()) {
294 download_crx_util::OpenChromeExtension(download_manager_->profile(),
295 *this);
296 return;
297 }
298 #if defined(OS_MACOSX)
299 // Mac OS X requires opening downloads on the UI thread.
300 platform_util::OpenItem(full_path());
301 #else
302 BrowserThread::PostTask(
303 BrowserThread::FILE, FROM_HERE,
304 NewRunnableFunction(&platform_util::OpenItem, full_path()));
305 #endif
306 }
307 }
308
309 void DownloadItem::ShowDownloadInShell() {
310 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
311 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
312
313 #if defined(OS_MACOSX)
314 // Mac needs to run this operation on the UI thread.
315 platform_util::ShowItemInFolder(full_path());
316 #else
317 BrowserThread::PostTask(
318 BrowserThread::FILE, FROM_HERE,
319 NewRunnableFunction(&platform_util::ShowItemInFolder,
320 full_path()));
321 #endif
322 }
323
324 void DownloadItem::DangerousDownloadValidated() {
325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
326 DCHECK_EQ(DANGEROUS, safety_state());
327
328 UMA_HISTOGRAM_ENUMERATION("Download.DangerousDownloadValidated",
329 GetDangerType(),
330 DANGEROUS_TYPE_MAX);
331
332 safety_state_ = DANGEROUS_BUT_VALIDATED;
333 UpdateObservers();
334
335 download_manager_->MaybeCompleteDownload(this);
336 }
337
338 void DownloadItem::UpdateSize(int64 bytes_so_far) {
339 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
340 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
341
342 received_bytes_ = bytes_so_far;
343
344 // If we've received more data than we were expecting (bad server info?),
345 // revert to 'unknown size mode'.
346 if (received_bytes_ > total_bytes_)
347 total_bytes_ = 0;
348 }
349
350 void DownloadItem::StartProgressTimer() {
351 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
352 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
353
354 update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdateTimeMs), this,
355 &DownloadItem::UpdateObservers);
356 }
357
358 void DownloadItem::StopProgressTimer() {
359 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
360 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
361
362 update_timer_.Stop();
363 }
364
365 // Updates from the download thread may have been posted while this download
366 // was being cancelled in the UI thread, so we'll accept them unless we're
367 // complete.
368 void DownloadItem::Update(int64 bytes_so_far) {
369 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
370 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
371
372 if (!IsInProgress()) {
373 NOTREACHED();
374 return;
375 }
376 UpdateSize(bytes_so_far);
377 UpdateObservers();
378 }
379
380 // Triggered by a user action.
381 void DownloadItem::Cancel(bool update_history) {
382 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
383 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
384
385 VLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
386 if (!IsPartialDownload()) {
387 // Small downloads might be complete before this method has
388 // a chance to run.
389 return;
390 }
391
392 download_util::RecordDownloadCount(download_util::CANCELLED_COUNT);
393
394 TransitionTo(CANCELLED);
395 StopProgressTimer();
396 if (update_history)
397 download_manager_->DownloadCancelled(download_id_);
398 }
399
400 void DownloadItem::MarkAsComplete() {
401 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
402 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
403
404 DCHECK(all_data_saved_);
405 TransitionTo(COMPLETE);
406 }
407
408 void DownloadItem::OnAllDataSaved(int64 size) {
409 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
410 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
411
412 DCHECK(!all_data_saved_);
413 all_data_saved_ = true;
414 UpdateSize(size);
415 StopProgressTimer();
416 }
417
418 void DownloadItem::OnDownloadedFileRemoved() {
419 file_externally_removed_ = true;
420 UpdateObservers();
421 }
422
423 void DownloadItem::Completed() {
424 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
425 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
426
427 VLOG(20) << __FUNCTION__ << "() " << DebugString(false);
428
429 DCHECK(all_data_saved_);
430 TransitionTo(COMPLETE);
431 download_manager_->DownloadCompleted(id());
432 download_util::RecordDownloadCompleted(start_tick_);
433
434 if (is_extension_install()) {
435 // Extensions should already have been unpacked and opened.
436 DCHECK(auto_opened_);
437 } else if (open_when_complete() ||
438 ShouldOpenFileBasedOnExtension() ||
439 is_temporary()) {
440 // If the download is temporary, like in drag-and-drop, do not open it but
441 // we still need to set it auto-opened so that it can be removed from the
442 // download shelf.
443 if (!is_temporary())
444 OpenDownload();
445
446 auto_opened_ = true;
447 UpdateObservers();
448 }
449 }
450
451 void DownloadItem::StartCrxInstall() {
452 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
453 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
454
455 DCHECK(is_extension_install());
456 DCHECK(all_data_saved_);
457
458 scoped_refptr<CrxInstaller> crx_installer =
459 download_crx_util::OpenChromeExtension(
460 download_manager_->profile(),
461 *this);
462
463 // CRX_INSTALLER_DONE will fire when the install completes. Observe()
464 // will call Completed() on this item. If this DownloadItem is not
465 // around when CRX_INSTALLER_DONE fires, Complete() will not be called.
466 registrar_.Add(this,
467 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
468 Source<CrxInstaller>(crx_installer.get()));
469
470 // The status text and percent complete indicator will change now
471 // that we are installing a CRX. Update observers so that they pick
472 // up the change.
473 UpdateObservers();
474 }
475
476 void DownloadItem::TransitionTo(DownloadState new_state) {
477 if (state_ == new_state)
478 return;
479
480 state_ = new_state;
481 UpdateObservers();
482 }
483
484 void DownloadItem::UpdateSafetyState() {
485 SafetyState updated_value(
486 GetSafetyState(state_info_.is_dangerous_file,
487 state_info_.is_dangerous_url));
488 if (updated_value != safety_state_) {
489 safety_state_ = updated_value;
490 UpdateObservers();
491 }
492 }
493
494 void DownloadItem::UpdateTarget() {
495 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
496 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
497
498 if (state_info_.target_name.value().empty())
499 state_info_.target_name = full_path_.BaseName();
500 }
501
502 // NotificationObserver implementation.
503 void DownloadItem::Observe(int type,
504 const NotificationSource& source,
505 const NotificationDetails& details) {
506 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
507 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
508
509 DCHECK(type == chrome::NOTIFICATION_CRX_INSTALLER_DONE);
510
511 // No need to listen for CRX_INSTALLER_DONE anymore.
512 registrar_.Remove(this,
513 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
514 source);
515
516 auto_opened_ = true;
517 DCHECK(all_data_saved_);
518
519 Completed();
520 }
521
522 void DownloadItem::Interrupted(int64 size, int os_error) {
523 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
524 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
525
526 if (!IsInProgress())
527 return;
528
529 last_os_error_ = os_error;
530 UpdateSize(size);
531 StopProgressTimer();
532 download_util::RecordDownloadInterrupted(os_error,
533 received_bytes_,
534 total_bytes_);
535 TransitionTo(INTERRUPTED);
536 }
537
538 void DownloadItem::Delete(DeleteReason reason) {
539 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
540 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
541
542 switch (reason) {
543 case DELETE_DUE_TO_USER_DISCARD:
544 UMA_HISTOGRAM_ENUMERATION("Download.UserDiscard", GetDangerType(),
545 DANGEROUS_TYPE_MAX);
546 break;
547 case DELETE_DUE_TO_BROWSER_SHUTDOWN:
548 UMA_HISTOGRAM_ENUMERATION("Download.Discard", GetDangerType(),
549 DANGEROUS_TYPE_MAX);
550 break;
551 default:
552 NOTREACHED();
553 }
554
555 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
556 NewRunnableFunction(&DeleteDownloadedFile, full_path_));
557 Remove();
558 // We have now been deleted.
559 }
560
561 void DownloadItem::Remove() {
562 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
563 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
564
565 download_manager_->AssertQueueStateConsistent(this);
566 Cancel(true);
567 download_manager_->AssertQueueStateConsistent(this);
568
569 TransitionTo(REMOVING);
570 download_manager_->RemoveDownload(db_handle_);
571 // We have now been deleted.
572 }
573
574 bool DownloadItem::TimeRemaining(base::TimeDelta* remaining) const {
575 if (total_bytes_ <= 0)
576 return false; // We never received the content_length for this download.
577
578 int64 speed = CurrentSpeed();
579 if (speed == 0)
580 return false;
581
582 *remaining = base::TimeDelta::FromSeconds(
583 (total_bytes_ - received_bytes_) / speed);
584 return true;
585 }
586
587 int64 DownloadItem::CurrentSpeed() const {
588 if (is_paused_)
589 return 0;
590 base::TimeDelta diff = base::TimeTicks::Now() - start_tick_;
591 int64 diff_ms = diff.InMilliseconds();
592 return diff_ms == 0 ? 0 : received_bytes_ * 1000 / diff_ms;
593 }
594
595 int DownloadItem::PercentComplete() const {
596 // We don't have an accurate way to estimate the time to unpack a CRX.
597 // The slowest part is re-encoding images, and time to do this depends on
598 // the contents of the image. If a CRX is being unpacked, indicate that
599 // we do not know how close to completion we are.
600 if (IsCrxInstallRuning() || total_bytes_ <= 0)
601 return -1;
602
603 return static_cast<int>(received_bytes_ * 100.0 / total_bytes_);
604 }
605
606 void DownloadItem::OnPathDetermined(const FilePath& path) {
607 full_path_ = path;
608 UpdateTarget();
609 }
610
611 void DownloadItem::Rename(const FilePath& full_path) {
612 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
613 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
614
615 VLOG(20) << __FUNCTION__ << "()"
616 << " full_path = \"" << full_path.value() << "\""
617 << " " << DebugString(true);
618 DCHECK(!full_path.empty());
619 full_path_ = full_path;
620 }
621
622 void DownloadItem::TogglePause() {
623 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
624 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
625
626 DCHECK(IsInProgress());
627 if (is_paused_)
628 request_handle_.ResumeRequest();
629 else
630 request_handle_.PauseRequest();
631 is_paused_ = !is_paused_;
632 UpdateObservers();
633 }
634
635 void DownloadItem::OnDownloadCompleting(DownloadFileManager* file_manager) {
636 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
637 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
638
639 VLOG(20) << __FUNCTION__ << "()"
640 << " needs rename = " << NeedsRename()
641 << " " << DebugString(true);
642 DCHECK_NE(DANGEROUS, safety_state());
643 DCHECK(file_manager);
644
645 if (NeedsRename()) {
646 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
647 NewRunnableMethod(file_manager,
648 &DownloadFileManager::RenameCompletingDownloadFile, id(),
649 GetTargetFilePath(), safety_state() == SAFE));
650 return;
651 }
652
653 DCHECK(!is_extension_install());
654 Completed();
655
656 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
657 NewRunnableMethod(file_manager, &DownloadFileManager::CompleteDownload,
658 id()));
659 }
660
661 void DownloadItem::OnDownloadRenamedToFinalName(const FilePath& full_path) {
662 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
663 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
664
665 VLOG(20) << __FUNCTION__ << "()"
666 << " full_path = \"" << full_path.value() << "\""
667 << " needed rename = " << NeedsRename()
668 << " " << DebugString(false);
669 DCHECK(NeedsRename());
670
671 Rename(full_path);
672
673 if (is_extension_install()) {
674 StartCrxInstall();
675 // Completed() will be called when the installer finishes.
676 return;
677 }
678
679 Completed();
680 }
681
682 bool DownloadItem::MatchesQuery(const string16& query) const {
683 if (query.empty())
684 return true;
685
686 DCHECK_EQ(query, base::i18n::ToLower(query));
687
688 string16 url_raw(base::i18n::ToLower(UTF8ToUTF16(GetURL().spec())));
689 if (url_raw.find(query) != string16::npos)
690 return true;
691
692 // TODO(phajdan.jr): write a test case for the following code.
693 // A good test case would be:
694 // "/\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xbd\xa0\xe5\xa5\xbd",
695 // L"/\x4f60\x597d\x4f60\x597d",
696 // "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD"
697 PrefService* prefs = download_manager_->profile()->GetPrefs();
698 std::string languages(prefs->GetString(prefs::kAcceptLanguages));
699 string16 url_formatted(
700 base::i18n::ToLower(net::FormatUrl(GetURL(), languages)));
701 if (url_formatted.find(query) != string16::npos)
702 return true;
703
704 string16 path(base::i18n::ToLower(full_path().LossyDisplayName()));
705 // This shouldn't just do a substring match; it is wrong for Unicode
706 // due to normalization and we have a fancier search-query system
707 // used elsewhere.
708 // http://code.google.com/p/chromium/issues/detail?id=71982
709 return (path.find(query) != string16::npos);
710 }
711
712 void DownloadItem::SetFileCheckResults(const DownloadStateInfo& state) {
713 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
714 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
715
716 VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true);
717 state_info_ = state;
718 VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true);
719
720 UpdateSafetyState();
721 }
722
723 DownloadItem::DangerType DownloadItem::GetDangerType() const {
724 return ::GetDangerType(state_info_.is_dangerous_file,
725 state_info_.is_dangerous_url);
726 }
727
728 bool DownloadItem::IsDangerous() const {
729 return GetDangerType() != DownloadItem::NOT_DANGEROUS;
730 }
731
732 void DownloadItem::MarkFileDangerous() {
733 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
734 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
735
736 state_info_.is_dangerous_file = true;
737 UpdateSafetyState();
738 }
739
740 void DownloadItem::MarkUrlDangerous() {
741 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
742 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
743
744 state_info_.is_dangerous_url = true;
745 UpdateSafetyState();
746 }
747
748 DownloadHistoryInfo DownloadItem::GetHistoryInfo() const {
749 return DownloadHistoryInfo(full_path(),
750 GetURL(),
751 referrer_url(),
752 start_time(),
753 received_bytes(),
754 total_bytes(),
755 state(),
756 db_handle());
757 }
758
759 FilePath DownloadItem::GetTargetFilePath() const {
760 return full_path_.DirName().Append(state_info_.target_name);
761 }
762
763 FilePath DownloadItem::GetFileNameToReportUser() const {
764 if (state_info_.path_uniquifier > 0) {
765 FilePath name(state_info_.target_name);
766 download_util::AppendNumberToPath(&name, state_info_.path_uniquifier);
767 return name;
768 }
769 return state_info_.target_name;
770 }
771
772 FilePath DownloadItem::GetUserVerifiedFilePath() const {
773 return (safety_state_ == DownloadItem::SAFE) ?
774 GetTargetFilePath() : full_path_;
775 }
776
777 void DownloadItem::Init(bool active) {
778 // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
779 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
780
781 UpdateTarget();
782 if (active) {
783 StartProgressTimer();
784 download_util::RecordDownloadCount(download_util::START_COUNT);
785 }
786 VLOG(20) << __FUNCTION__ << "() " << DebugString(true);
787 }
788
789 // TODO(ahendrickson) -- Move |INTERRUPTED| from |IsCancelled()| to
790 // |IsPartialDownload()|, when resuming interrupted downloads is implemented.
791 bool DownloadItem::IsPartialDownload() const {
792 return (state_ == IN_PROGRESS);
793 }
794
795 bool DownloadItem::IsInProgress() const {
796 return (state_ == IN_PROGRESS);
797 }
798
799 bool DownloadItem::IsCancelled() const {
800 return (state_ == CANCELLED) ||
801 (state_ == INTERRUPTED);
802 }
803
804 bool DownloadItem::IsInterrupted() const {
805 return (state_ == INTERRUPTED);
806 }
807
808 bool DownloadItem::IsComplete() const {
809 return (state_ == COMPLETE);
810 }
811
812 const GURL& DownloadItem::GetURL() const {
813 return url_chain_.empty() ?
814 GURL::EmptyGURL() : url_chain_.back();
815 }
816
817 std::string DownloadItem::DebugString(bool verbose) const {
818 std::string description =
819 base::StringPrintf("{ id = %d"
820 " state = %s",
821 download_id_,
822 DebugDownloadStateString(state()));
823
824 // Construct a string of the URL chain.
825 std::string url_list("<none>");
826 if (!url_chain_.empty()) {
827 std::vector<GURL>::const_iterator iter = url_chain_.begin();
828 std::vector<GURL>::const_iterator last = url_chain_.end();
829 url_list = (*iter).spec();
830 ++iter;
831 for ( ; verbose && (iter != last); ++iter) {
832 url_list += " ->\n\t";
833 const GURL& next_url = *iter;
834 url_list += next_url.spec();
835 }
836 }
837
838 if (verbose) {
839 description += base::StringPrintf(
840 " db_handle = %" PRId64
841 " total_bytes = %" PRId64
842 " received_bytes = %" PRId64
843 " is_paused = %c"
844 " is_extension_install = %c"
845 " is_otr = %c"
846 " safety_state = %s"
847 " url_chain = \n\t\"%s\"\n\t"
848 " target_name = \"%" PRFilePath "\""
849 " full_path = \"%" PRFilePath "\"",
850 db_handle(),
851 total_bytes(),
852 received_bytes(),
853 is_paused() ? 'T' : 'F',
854 is_extension_install() ? 'T' : 'F',
855 is_otr() ? 'T' : 'F',
856 DebugSafetyStateString(safety_state()),
857 url_list.c_str(),
858 state_info_.target_name.value().c_str(),
859 full_path().value().c_str());
860 } else {
861 description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
862 }
863
864 description += " }";
865
866 return description;
867 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698