OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 #include "chrome/browser/download/download_target_determiner.h" | 5 #include "chrome/browser/download/download_target_determiner.h" |
6 | 6 |
7 #include "base/prefs/pref_service.h" | 7 #include "base/prefs/pref_service.h" |
8 #include "base/rand_util.h" | 8 #include "base/rand_util.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
11 #include "chrome/browser/download/chrome_download_manager_delegate.h" | 11 #include "chrome/browser/download/chrome_download_manager_delegate.h" |
12 #include "chrome/browser/download/download_crx_util.h" | 12 #include "chrome/browser/download/download_crx_util.h" |
13 #include "chrome/browser/download/download_extensions.h" | 13 #include "chrome/browser/download/download_extensions.h" |
14 #include "chrome/browser/download/download_prefs.h" | 14 #include "chrome/browser/download/download_prefs.h" |
15 #include "chrome/browser/extensions/webstore_installer.h" | 15 #include "chrome/browser/extensions/webstore_installer.h" |
16 #include "chrome/browser/history/history_service.h" | 16 #include "chrome/browser/history/history_service.h" |
17 #include "chrome/browser/history/history_service_factory.h" | 17 #include "chrome/browser/history/history_service_factory.h" |
18 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
19 #include "chrome/common/extensions/feature_switch.h" | 19 #include "chrome/common/extensions/feature_switch.h" |
20 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
21 #include "content/public/browser/browser_context.h" | 21 #include "content/public/browser/browser_context.h" |
22 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
23 #include "content/public/browser/download_interrupt_reasons.h" | 23 #include "content/public/browser/download_interrupt_reasons.h" |
24 #include "extensions/common/constants.h" | 24 #include "extensions/common/constants.h" |
25 #include "grit/generated_resources.h" | 25 #include "grit/generated_resources.h" |
26 #include "net/base/mime_util.h" | |
26 #include "net/base/net_util.h" | 27 #include "net/base/net_util.h" |
27 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
28 | 29 |
30 #if defined(ENABLE_PLUGINS) | |
31 #include "chrome/browser/plugins/plugin_prefs.h" | |
32 #include "content/public/browser/plugin_service.h" | |
33 #include "content/public/common/webplugininfo.h" | |
34 #endif | |
35 | |
29 using content::BrowserThread; | 36 using content::BrowserThread; |
30 using content::DownloadItem; | 37 using content::DownloadItem; |
31 | 38 |
32 namespace { | 39 namespace { |
33 | 40 |
34 const base::FilePath::CharType kCrdownloadSuffix[] = | 41 const base::FilePath::CharType kCrdownloadSuffix[] = |
35 FILE_PATH_LITERAL(".crdownload"); | 42 FILE_PATH_LITERAL(".crdownload"); |
36 | 43 |
37 // Condenses the results from HistoryService::GetVisibleVisitCountToHost() to a | 44 // Condenses the results from HistoryService::GetVisibleVisitCountToHost() to a |
38 // single bool. A host is considered visited before if prior visible visits were | 45 // single bool. A host is considered visited before if prior visible visits were |
39 // found in history and the first such visit was earlier than the most recent | 46 // found in history and the first such visit was earlier than the most recent |
40 // midnight. | 47 // midnight. |
41 void VisitCountsToVisitedBefore( | 48 void VisitCountsToVisitedBefore( |
42 const base::Callback<void(bool)>& callback, | 49 const base::Callback<void(bool)>& callback, |
43 HistoryService::Handle unused_handle, | 50 HistoryService::Handle unused_handle, |
44 bool found_visits, | 51 bool found_visits, |
45 int count, | 52 int count, |
46 base::Time first_visit) { | 53 base::Time first_visit) { |
47 callback.Run( | 54 callback.Run( |
48 found_visits && count > 0 && | 55 found_visits && count > 0 && |
49 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); | 56 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); |
50 } | 57 } |
51 | 58 |
59 #if defined(ENABLE_PLUGINS) | |
60 typedef std::vector<content::WebPluginInfo> PluginVector; | |
61 | |
62 bool IsSafePluginAvailableForProfile(scoped_ptr<PluginVector> plugins, | |
63 Profile* profile) { | |
64 using content::WebPluginInfo; | |
65 | |
66 if (plugins->size() == 0) | |
67 return false; | |
68 | |
69 scoped_refptr<PluginPrefs> plugin_prefs = PluginPrefs::GetForProfile(profile); | |
70 if (!plugin_prefs) | |
71 return false; | |
72 | |
73 for (PluginVector::iterator plugin = plugins->begin(); | |
74 plugin != plugins->end(); ++plugin) { | |
75 if (plugin_prefs->IsPluginEnabled(*plugin) && | |
76 (plugin->type == WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS || | |
77 plugin->type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS)) | |
78 return true; | |
79 } | |
80 return false; | |
81 } | |
82 | |
83 base::Callback<bool(Profile*)> GetPluginListVerifier( | |
84 const std::string& mime_type) { | |
85 DCHECK(!mime_type.empty()); | |
86 | |
87 scoped_ptr<PluginVector> plugins(new PluginVector); | |
88 content::PluginService* plugin_service = | |
89 content::PluginService::GetInstance(); | |
90 if (plugin_service) | |
91 plugin_service->GetPluginInfoArray( | |
92 GURL(), mime_type, false, plugins.get(), NULL); | |
93 return base::Bind(&IsSafePluginAvailableForProfile, base::Passed(&plugins)); | |
94 } | |
95 #endif // ENABLE_PLUGINS | |
Randy Smith (Not in Mondays)
2013/11/04 19:53:26
I'm a bit torn about this code organization. On t
asanka
2013/11/04 21:20:11
I tried that, but it still seemed a bit confusing.
| |
96 | |
52 } // namespace | 97 } // namespace |
53 | 98 |
99 DownloadTargetInfo::DownloadTargetInfo() | |
100 : is_filetype_handled_securely(false) {} | |
101 | |
102 DownloadTargetInfo::~DownloadTargetInfo() {} | |
103 | |
54 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() { | 104 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() { |
55 } | 105 } |
56 | 106 |
57 DownloadTargetDeterminer::DownloadTargetDeterminer( | 107 DownloadTargetDeterminer::DownloadTargetDeterminer( |
58 DownloadItem* download, | 108 DownloadItem* download, |
59 const base::FilePath& initial_virtual_path, | 109 const base::FilePath& initial_virtual_path, |
60 DownloadPrefs* download_prefs, | 110 DownloadPrefs* download_prefs, |
61 DownloadTargetDeterminerDelegate* delegate, | 111 DownloadTargetDeterminerDelegate* delegate, |
62 const content::DownloadTargetCallback& callback) | 112 const CompletionCallback& callback) |
63 : next_state_(STATE_GENERATE_TARGET_PATH), | 113 : next_state_(STATE_GENERATE_TARGET_PATH), |
64 should_prompt_(false), | 114 should_prompt_(false), |
65 should_notify_extensions_(false), | 115 should_notify_extensions_(false), |
66 create_target_directory_(false), | 116 create_target_directory_(false), |
67 conflict_action_(DownloadPathReservationTracker::OVERWRITE), | 117 conflict_action_(DownloadPathReservationTracker::OVERWRITE), |
68 danger_type_(download->GetDangerType()), | 118 danger_type_(download->GetDangerType()), |
69 virtual_path_(initial_virtual_path), | 119 virtual_path_(initial_virtual_path), |
120 is_filetype_handled_securely_(false), | |
70 download_(download), | 121 download_(download), |
71 is_resumption_(download_->GetLastReason() != | 122 is_resumption_(download_->GetLastReason() != |
72 content::DOWNLOAD_INTERRUPT_REASON_NONE && | 123 content::DOWNLOAD_INTERRUPT_REASON_NONE && |
73 !initial_virtual_path.empty()), | 124 !initial_virtual_path.empty()), |
74 download_prefs_(download_prefs), | 125 download_prefs_(download_prefs), |
75 delegate_(delegate), | 126 delegate_(delegate), |
76 completion_callback_(callback), | 127 completion_callback_(callback), |
77 weak_ptr_factory_(this) { | 128 weak_ptr_factory_(this) { |
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
79 DCHECK(download_); | 130 DCHECK(download_); |
(...skipping 25 matching lines...) Expand all Loading... | |
105 break; | 156 break; |
106 case STATE_RESERVE_VIRTUAL_PATH: | 157 case STATE_RESERVE_VIRTUAL_PATH: |
107 result = DoReserveVirtualPath(); | 158 result = DoReserveVirtualPath(); |
108 break; | 159 break; |
109 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH: | 160 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH: |
110 result = DoPromptUserForDownloadPath(); | 161 result = DoPromptUserForDownloadPath(); |
111 break; | 162 break; |
112 case STATE_DETERMINE_LOCAL_PATH: | 163 case STATE_DETERMINE_LOCAL_PATH: |
113 result = DoDetermineLocalPath(); | 164 result = DoDetermineLocalPath(); |
114 break; | 165 break; |
166 case STATE_DETERMINE_MIME_TYPE: | |
167 result = DoDetermineMimeType(); | |
168 break; | |
169 case STATE_DETERMINE_IF_HANDLED_BY_BROWSER: | |
170 result = DoDetermineIfHandledByBrowser(); | |
171 break; | |
115 case STATE_CHECK_DOWNLOAD_URL: | 172 case STATE_CHECK_DOWNLOAD_URL: |
116 result = DoCheckDownloadUrl(); | 173 result = DoCheckDownloadUrl(); |
117 break; | 174 break; |
118 case STATE_DETERMINE_INTERMEDIATE_PATH: | 175 case STATE_DETERMINE_INTERMEDIATE_PATH: |
119 result = DoDetermineIntermediatePath(); | 176 result = DoDetermineIntermediatePath(); |
120 break; | 177 break; |
121 case STATE_CHECK_VISITED_REFERRER_BEFORE: | 178 case STATE_CHECK_VISITED_REFERRER_BEFORE: |
122 result = DoCheckVisitedReferrerBefore(); | 179 result = DoCheckVisitedReferrerBefore(); |
123 break; | 180 break; |
124 case STATE_NONE: | 181 case STATE_NONE: |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
298 download_prefs_->SetSaveFilePath(virtual_path_.DirName()); | 355 download_prefs_->SetSaveFilePath(virtual_path_.DirName()); |
299 DoLoop(); | 356 DoLoop(); |
300 } | 357 } |
301 | 358 |
302 DownloadTargetDeterminer::Result | 359 DownloadTargetDeterminer::Result |
303 DownloadTargetDeterminer::DoDetermineLocalPath() { | 360 DownloadTargetDeterminer::DoDetermineLocalPath() { |
304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
305 DCHECK(!virtual_path_.empty()); | 362 DCHECK(!virtual_path_.empty()); |
306 DCHECK(local_path_.empty()); | 363 DCHECK(local_path_.empty()); |
307 | 364 |
308 next_state_ = STATE_CHECK_DOWNLOAD_URL; | 365 next_state_ = STATE_DETERMINE_MIME_TYPE; |
309 | 366 |
310 delegate_->DetermineLocalPath( | 367 delegate_->DetermineLocalPath( |
311 download_, | 368 download_, |
312 virtual_path_, | 369 virtual_path_, |
313 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone, | 370 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone, |
314 weak_ptr_factory_.GetWeakPtr())); | 371 weak_ptr_factory_.GetWeakPtr())); |
315 return QUIT_DOLOOP; | 372 return QUIT_DOLOOP; |
316 } | 373 } |
317 | 374 |
318 void DownloadTargetDeterminer::DetermineLocalPathDone( | 375 void DownloadTargetDeterminer::DetermineLocalPathDone( |
319 const base::FilePath& local_path) { | 376 const base::FilePath& local_path) { |
320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
321 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe(); | 378 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe(); |
322 if (local_path.empty()) { | 379 if (local_path.empty()) { |
323 // Path subsitution failed. | 380 // Path subsitution failed. |
324 CancelOnFailureAndDeleteSelf(); | 381 CancelOnFailureAndDeleteSelf(); |
325 return; | 382 return; |
326 } | 383 } |
327 local_path_ = local_path; | 384 local_path_ = local_path; |
328 DoLoop(); | 385 DoLoop(); |
329 } | 386 } |
330 | 387 |
331 DownloadTargetDeterminer::Result | 388 DownloadTargetDeterminer::Result |
389 DownloadTargetDeterminer::DoDetermineMimeType() { | |
390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
391 DCHECK(!virtual_path_.empty()); | |
392 DCHECK(!local_path_.empty()); | |
393 DCHECK(mime_type_.empty()); | |
394 | |
395 next_state_ = STATE_DETERMINE_IF_HANDLED_BY_BROWSER; | |
396 | |
397 if (virtual_path_ == local_path_) { | |
398 delegate_->GetFileMimeType( | |
399 local_path_, | |
400 base::Bind(&DownloadTargetDeterminer::DetermineMimeTypeDone, | |
401 weak_ptr_factory_.GetWeakPtr())); | |
402 return QUIT_DOLOOP; | |
403 } | |
404 return CONTINUE; | |
405 } | |
406 | |
407 void DownloadTargetDeterminer::DetermineMimeTypeDone( | |
408 const std::string& mime_type) { | |
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
410 DVLOG(20) << "MIME type: " << mime_type; | |
411 mime_type_ = mime_type; | |
412 DoLoop(); | |
413 } | |
414 | |
415 DownloadTargetDeterminer::Result | |
416 DownloadTargetDeterminer::DoDetermineIfHandledByBrowser() { | |
417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
418 DCHECK(!virtual_path_.empty()); | |
419 DCHECK(!local_path_.empty()); | |
420 DCHECK(!is_filetype_handled_securely_); | |
421 | |
422 next_state_ = STATE_CHECK_DOWNLOAD_URL; | |
423 | |
424 if (mime_type_.empty()) | |
425 return CONTINUE; | |
426 | |
427 if (net::IsSupportedMimeType(mime_type_)) { | |
428 is_filetype_handled_securely_ = true; | |
429 return CONTINUE; | |
430 } | |
431 | |
432 BrowserThread::PostTaskAndReplyWithResult( | |
433 BrowserThread::IO, | |
434 FROM_HERE, | |
435 base::Bind(&GetPluginListVerifier, mime_type_), | |
436 base::Bind(&DownloadTargetDeterminer::DetermineIfHandledByBrowserDone, | |
437 weak_ptr_factory_.GetWeakPtr())); | |
438 return QUIT_DOLOOP; | |
439 } | |
440 | |
441 void DownloadTargetDeterminer::DetermineIfHandledByBrowserDone( | |
442 const base::Callback<bool(Profile*)>& callback) { | |
443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
444 is_filetype_handled_securely_ = callback.Run(GetProfile()); | |
445 DVLOG(20) << "Is file type handled securely: " | |
446 << is_filetype_handled_securely_; | |
447 DoLoop(); | |
448 } | |
449 | |
450 DownloadTargetDeterminer::Result | |
332 DownloadTargetDeterminer::DoCheckDownloadUrl() { | 451 DownloadTargetDeterminer::DoCheckDownloadUrl() { |
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 452 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
334 DCHECK(!virtual_path_.empty()); | 453 DCHECK(!virtual_path_.empty()); |
335 next_state_ = STATE_CHECK_VISITED_REFERRER_BEFORE; | 454 next_state_ = STATE_CHECK_VISITED_REFERRER_BEFORE; |
336 delegate_->CheckDownloadUrl( | 455 delegate_->CheckDownloadUrl( |
337 download_, | 456 download_, |
338 virtual_path_, | 457 virtual_path_, |
339 base::Bind(&DownloadTargetDeterminer::CheckDownloadUrlDone, | 458 base::Bind(&DownloadTargetDeterminer::CheckDownloadUrlDone, |
340 weak_ptr_factory_.GetWeakPtr())); | 459 weak_ptr_factory_.GetWeakPtr())); |
341 return QUIT_DOLOOP; | 460 return QUIT_DOLOOP; |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
477 return COMPLETE; | 596 return COMPLETE; |
478 } | 597 } |
479 | 598 |
480 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() { | 599 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() { |
481 DCHECK(download_); | 600 DCHECK(download_); |
482 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe() | 601 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe() |
483 << " Local:" << local_path_.AsUTF8Unsafe() | 602 << " Local:" << local_path_.AsUTF8Unsafe() |
484 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe() | 603 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe() |
485 << " Should prompt:" << should_prompt_ | 604 << " Should prompt:" << should_prompt_ |
486 << " Danger type:" << danger_type_; | 605 << " Danger type:" << danger_type_; |
606 scoped_ptr<DownloadTargetInfo> target_info(new DownloadTargetInfo); | |
607 | |
608 target_info->target_path = local_path_; | |
609 target_info->target_disposition = | |
610 (HasPromptedForPath() || should_prompt_ | |
611 ? DownloadItem::TARGET_DISPOSITION_PROMPT | |
612 : DownloadItem::TARGET_DISPOSITION_OVERWRITE); | |
613 target_info->danger_type = danger_type_; | |
614 target_info->intermediate_path = intermediate_path_; | |
615 target_info->mime_type = mime_type_; | |
616 target_info->is_filetype_handled_securely = is_filetype_handled_securely_; | |
Randy Smith (Not in Mondays)
2013/11/04 19:53:26
Long-term thought: One of the goals I had for the
asanka
2013/11/04 21:20:11
Yup. We can look at it when we revisit the handlin
| |
617 | |
487 base::MessageLoop::current()->PostTask( | 618 base::MessageLoop::current()->PostTask( |
488 FROM_HERE, | 619 FROM_HERE, base::Bind(completion_callback_, base::Passed(&target_info))); |
489 base::Bind(completion_callback_, | |
490 local_path_, | |
491 (HasPromptedForPath() || should_prompt_ | |
492 ? DownloadItem::TARGET_DISPOSITION_PROMPT | |
493 : DownloadItem::TARGET_DISPOSITION_OVERWRITE), | |
494 danger_type_, | |
495 intermediate_path_)); | |
496 completion_callback_.Reset(); | 620 completion_callback_.Reset(); |
497 delete this; | 621 delete this; |
498 } | 622 } |
499 | 623 |
500 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() { | 624 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() { |
501 // Path substitution failed. | 625 // Path substitution failed. |
502 virtual_path_.clear(); | 626 virtual_path_.clear(); |
503 local_path_.clear(); | 627 local_path_.clear(); |
504 intermediate_path_.clear(); | 628 intermediate_path_.clear(); |
505 ScheduleCallbackAndDeleteSelf(); | 629 ScheduleCallbackAndDeleteSelf(); |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
624 } | 748 } |
625 | 749 |
626 void DownloadTargetDeterminer::OnDownloadDestroyed( | 750 void DownloadTargetDeterminer::OnDownloadDestroyed( |
627 DownloadItem* download) { | 751 DownloadItem* download) { |
628 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 752 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
629 DCHECK_EQ(download_, download); | 753 DCHECK_EQ(download_, download); |
630 CancelOnFailureAndDeleteSelf(); | 754 CancelOnFailureAndDeleteSelf(); |
631 } | 755 } |
632 | 756 |
633 // static | 757 // static |
634 void DownloadTargetDeterminer::Start( | 758 void DownloadTargetDeterminer::Start(content::DownloadItem* download, |
635 content::DownloadItem* download, | 759 const base::FilePath& initial_virtual_path, |
636 const base::FilePath& initial_virtual_path, | 760 DownloadPrefs* download_prefs, |
637 DownloadPrefs* download_prefs, | 761 DownloadTargetDeterminerDelegate* delegate, |
638 DownloadTargetDeterminerDelegate* delegate, | 762 const CompletionCallback& callback) { |
639 const content::DownloadTargetCallback& callback) { | |
640 // DownloadTargetDeterminer owns itself and will self destruct when the job is | 763 // DownloadTargetDeterminer owns itself and will self destruct when the job is |
641 // complete or the download item is destroyed. The callback is always invoked | 764 // complete or the download item is destroyed. The callback is always invoked |
642 // asynchronously. | 765 // asynchronously. |
643 new DownloadTargetDeterminer(download, initial_virtual_path, download_prefs, | 766 new DownloadTargetDeterminer(download, initial_virtual_path, download_prefs, |
644 delegate, callback); | 767 delegate, callback); |
645 } | 768 } |
646 | 769 |
647 // static | 770 // static |
648 base::FilePath DownloadTargetDeterminer::GetCrDownloadPath( | 771 base::FilePath DownloadTargetDeterminer::GetCrDownloadPath( |
649 const base::FilePath& suggested_path) { | 772 const base::FilePath& suggested_path) { |
650 return base::FilePath(suggested_path.value() + kCrdownloadSuffix); | 773 return base::FilePath(suggested_path.value() + kCrdownloadSuffix); |
651 } | 774 } |
OLD | NEW |