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 #include "chrome/browser/extensions/api/downloads/downloads_api.h" | 5 #include "chrome/browser/extensions/api/downloads/downloads_api.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cctype> | 8 #include <cctype> |
9 #include <iterator> | 9 #include <iterator> |
10 #include <set> | 10 #include <set> |
(...skipping 26 matching lines...) Expand all Loading... |
37 #include "chrome/browser/download/download_service_factory.h" | 37 #include "chrome/browser/download/download_service_factory.h" |
38 #include "chrome/browser/download/download_shelf.h" | 38 #include "chrome/browser/download/download_shelf.h" |
39 #include "chrome/browser/download/download_util.h" | 39 #include "chrome/browser/download/download_util.h" |
40 #include "chrome/browser/extensions/event_names.h" | 40 #include "chrome/browser/extensions/event_names.h" |
41 #include "chrome/browser/extensions/event_router.h" | 41 #include "chrome/browser/extensions/event_router.h" |
42 #include "chrome/browser/extensions/extension_function_dispatcher.h" | 42 #include "chrome/browser/extensions/extension_function_dispatcher.h" |
43 #include "chrome/browser/extensions/extension_info_map.h" | 43 #include "chrome/browser/extensions/extension_info_map.h" |
44 #include "chrome/browser/extensions/extension_prefs.h" | 44 #include "chrome/browser/extensions/extension_prefs.h" |
45 #include "chrome/browser/extensions/extension_service.h" | 45 #include "chrome/browser/extensions/extension_service.h" |
46 #include "chrome/browser/extensions/extension_system.h" | 46 #include "chrome/browser/extensions/extension_system.h" |
| 47 #include "chrome/browser/extensions/extension_warning_service.h" |
| 48 #include "chrome/browser/extensions/extension_warning_set.h" |
47 #include "chrome/browser/icon_loader.h" | 49 #include "chrome/browser/icon_loader.h" |
48 #include "chrome/browser/icon_manager.h" | 50 #include "chrome/browser/icon_manager.h" |
49 #include "chrome/browser/platform_util.h" | 51 #include "chrome/browser/platform_util.h" |
50 #include "chrome/browser/profiles/profile.h" | 52 #include "chrome/browser/profiles/profile.h" |
51 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" | 53 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
52 #include "chrome/browser/ui/browser.h" | 54 #include "chrome/browser/ui/browser.h" |
53 #include "chrome/browser/ui/browser_list.h" | 55 #include "chrome/browser/ui/browser_list.h" |
54 #include "chrome/browser/ui/browser_window.h" | 56 #include "chrome/browser/ui/browser_window.h" |
55 #include "chrome/common/cancelable_task_tracker.h" | 57 #include "chrome/common/cancelable_task_tracker.h" |
56 #include "chrome/common/extensions/api/downloads.h" | 58 #include "chrome/common/extensions/api/downloads.h" |
(...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 explicit ExtensionDownloadsEventRouterData( | 587 explicit ExtensionDownloadsEventRouterData( |
586 DownloadItem* download_item, | 588 DownloadItem* download_item, |
587 scoped_ptr<base::DictionaryValue> json_item) | 589 scoped_ptr<base::DictionaryValue> json_item) |
588 : updated_(0), | 590 : updated_(0), |
589 changed_fired_(0), | 591 changed_fired_(0), |
590 json_(json_item.Pass()), | 592 json_(json_item.Pass()), |
591 creator_conflict_action_( | 593 creator_conflict_action_( |
592 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY), | 594 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY), |
593 determined_conflict_action_( | 595 determined_conflict_action_( |
594 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) { | 596 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) { |
| 597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
595 download_item->SetUserData(kKey, this); | 598 download_item->SetUserData(kKey, this); |
596 } | 599 } |
597 | 600 |
598 virtual ~ExtensionDownloadsEventRouterData() { | 601 virtual ~ExtensionDownloadsEventRouterData() { |
599 if (updated_ > 0) { | 602 if (updated_ > 0) { |
600 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", | 603 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", |
601 (changed_fired_ * 100 / updated_)); | 604 (changed_fired_ * 100 / updated_)); |
602 } | 605 } |
603 } | 606 } |
604 | 607 |
605 const base::DictionaryValue& json() const { return *json_.get(); } | 608 const base::DictionaryValue& json() const { return *json_.get(); } |
606 void set_json(scoped_ptr<base::DictionaryValue> json_item) { | 609 void set_json(scoped_ptr<base::DictionaryValue> json_item) { |
607 json_ = json_item.Pass(); | 610 json_ = json_item.Pass(); |
608 } | 611 } |
609 | 612 |
610 void OnItemUpdated() { ++updated_; } | 613 void OnItemUpdated() { ++updated_; } |
611 void OnChangedFired() { ++changed_fired_; } | 614 void OnChangedFired() { ++changed_fired_; } |
612 | 615 |
613 void set_filename_change_callbacks( | 616 void set_filename_change_callbacks( |
614 const base::Closure& no_change, | 617 const base::Closure& no_change, |
615 const ExtensionDownloadsEventRouter::FilenameChangedCallback& change) { | 618 const ExtensionDownloadsEventRouter::FilenameChangedCallback& change) { |
| 619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
616 filename_no_change_ = no_change; | 620 filename_no_change_ = no_change; |
617 filename_change_ = change; | 621 filename_change_ = change; |
618 determined_filename_ = creator_suggested_filename_; | 622 determined_filename_ = creator_suggested_filename_; |
619 determined_conflict_action_ = creator_conflict_action_; | 623 determined_conflict_action_ = creator_conflict_action_; |
620 // determiner_.install_time should default to 0 so that creator suggestions | 624 // determiner_.install_time should default to 0 so that creator suggestions |
621 // should be lower priority than any actual onDeterminingFilename listeners. | 625 // should be lower priority than any actual onDeterminingFilename listeners. |
622 } | 626 } |
623 | 627 |
624 void ClearPendingDeterminers() { | 628 void ClearPendingDeterminers() { |
| 629 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
625 determined_filename_.clear(); | 630 determined_filename_.clear(); |
626 determined_conflict_action_ = | 631 determined_conflict_action_ = |
627 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY; | 632 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY; |
628 determiner_ = DeterminerInfo(); | 633 determiner_ = DeterminerInfo(); |
629 filename_no_change_ = base::Closure(); | 634 filename_no_change_ = base::Closure(); |
630 filename_change_ = ExtensionDownloadsEventRouter::FilenameChangedCallback(); | 635 filename_change_ = ExtensionDownloadsEventRouter::FilenameChangedCallback(); |
631 weak_ptr_factory_.reset(); | 636 weak_ptr_factory_.reset(); |
632 determiners_.clear(); | 637 determiners_.clear(); |
633 } | 638 } |
634 | 639 |
635 void DeterminerRemoved(const std::string& extension_id) { | 640 void DeterminerRemoved(const std::string& extension_id) { |
| 641 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
636 for (DeterminerInfoVector::iterator iter = determiners_.begin(); | 642 for (DeterminerInfoVector::iterator iter = determiners_.begin(); |
637 iter != determiners_.end();) { | 643 iter != determiners_.end();) { |
638 if (iter->extension_id == extension_id) { | 644 if (iter->extension_id == extension_id) { |
639 iter = determiners_.erase(iter); | 645 iter = determiners_.erase(iter); |
640 } else { | 646 } else { |
641 ++iter; | 647 ++iter; |
642 } | 648 } |
643 } | 649 } |
644 // If we just removed the last unreported determiner, then we need to call a | 650 // If we just removed the last unreported determiner, then we need to call a |
645 // callback. | 651 // callback. |
646 CheckAllDeterminersCalled(); | 652 CheckAllDeterminersCalled(); |
647 } | 653 } |
648 | 654 |
649 void AddPendingDeterminer(const std::string& extension_id, | 655 void AddPendingDeterminer(const std::string& extension_id, |
650 const base::Time& installed) { | 656 const base::Time& installed) { |
| 657 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
651 for (size_t index = 0; index < determiners_.size(); ++index) { | 658 for (size_t index = 0; index < determiners_.size(); ++index) { |
652 if (determiners_[index].extension_id == extension_id) { | 659 if (determiners_[index].extension_id == extension_id) { |
653 DCHECK(false) << extension_id; | 660 DCHECK(false) << extension_id; |
654 return; | 661 return; |
655 } | 662 } |
656 } | 663 } |
657 determiners_.push_back(DeterminerInfo(extension_id, installed)); | 664 determiners_.push_back(DeterminerInfo(extension_id, installed)); |
658 } | 665 } |
659 | 666 |
660 bool DeterminerAlreadyReported(const std::string& extension_id) { | 667 bool DeterminerAlreadyReported(const std::string& extension_id) { |
| 668 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
661 for (size_t index = 0; index < determiners_.size(); ++index) { | 669 for (size_t index = 0; index < determiners_.size(); ++index) { |
662 if (determiners_[index].extension_id == extension_id) { | 670 if (determiners_[index].extension_id == extension_id) { |
663 return determiners_[index].reported; | 671 return determiners_[index].reported; |
664 } | 672 } |
665 } | 673 } |
666 return false; | 674 return false; |
667 } | 675 } |
668 | 676 |
669 void CreatorSuggestedFilename( | 677 void CreatorSuggestedFilename( |
670 const base::FilePath& filename, | 678 const base::FilePath& filename, |
671 extensions::api::downloads::FilenameConflictAction conflict_action) { | 679 extensions::api::downloads::FilenameConflictAction conflict_action) { |
| 680 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
672 creator_suggested_filename_ = filename; | 681 creator_suggested_filename_ = filename; |
673 creator_conflict_action_ = conflict_action; | 682 creator_conflict_action_ = conflict_action; |
674 } | 683 } |
675 | 684 |
676 base::FilePath creator_suggested_filename() const { | 685 base::FilePath creator_suggested_filename() const { |
677 return creator_suggested_filename_; | 686 return creator_suggested_filename_; |
678 } | 687 } |
679 | 688 |
680 extensions::api::downloads::FilenameConflictAction | 689 extensions::api::downloads::FilenameConflictAction |
681 creator_conflict_action() const { | 690 creator_conflict_action() const { |
682 return creator_conflict_action_; | 691 return creator_conflict_action_; |
683 } | 692 } |
684 | 693 |
685 void ResetCreatorSuggestion() { | 694 void ResetCreatorSuggestion() { |
| 695 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
686 creator_suggested_filename_.clear(); | 696 creator_suggested_filename_.clear(); |
687 creator_conflict_action_ = | 697 creator_conflict_action_ = |
688 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY; | 698 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY; |
689 } | 699 } |
690 | 700 |
691 // Returns false if this |extension_id| was not expected or if this | 701 // Returns false if this |extension_id| was not expected or if this |
692 // |extension_id| has already reported. The caller is responsible for | 702 // |extension_id| has already reported. The caller is responsible for |
693 // validating |filename|. | 703 // validating |filename|. |
694 bool DeterminerCallback( | 704 bool DeterminerCallback( |
| 705 Profile* profile, |
695 const std::string& extension_id, | 706 const std::string& extension_id, |
696 const base::FilePath& filename, | 707 const base::FilePath& filename, |
697 extensions::api::downloads::FilenameConflictAction conflict_action) { | 708 extensions::api::downloads::FilenameConflictAction conflict_action) { |
| 709 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
698 bool found_info = false; | 710 bool found_info = false; |
699 for (size_t index = 0; index < determiners_.size(); ++index) { | 711 for (size_t index = 0; index < determiners_.size(); ++index) { |
700 if (determiners_[index].extension_id == extension_id) { | 712 if (determiners_[index].extension_id == extension_id) { |
701 found_info = true; | 713 found_info = true; |
702 if (determiners_[index].reported) | 714 if (determiners_[index].reported) |
703 return false; | 715 return false; |
704 determiners_[index].reported = true; | 716 determiners_[index].reported = true; |
705 // Do not use filename if another determiner has already overridden the | 717 // Do not use filename if another determiner has already overridden the |
706 // filename and they take precedence. Extensions that were installed | 718 // filename and they take precedence. Extensions that were installed |
707 // later take precedence over previous extensions. | 719 // later take precedence over previous extensions. |
708 if (!filename.empty() && | 720 if (!filename.empty()) { |
709 (determiner_.extension_id.empty() || | 721 extensions::ExtensionWarningSet warnings; |
710 (determiners_[index].install_time > determiner_.install_time))) { | 722 std::string winner_extension_id; |
711 determined_filename_ = filename; | 723 ExtensionDownloadsEventRouter::DetermineFilenameInternal( |
712 determined_conflict_action_ = conflict_action; | 724 filename, |
713 determiner_ = determiners_[index]; | 725 conflict_action, |
| 726 determiners_[index].extension_id, |
| 727 determiners_[index].install_time, |
| 728 determiner_.extension_id, |
| 729 determiner_.install_time, |
| 730 &winner_extension_id, |
| 731 &determined_filename_, |
| 732 &determined_conflict_action_, |
| 733 &warnings); |
| 734 if (!warnings.empty()) |
| 735 extensions::ExtensionWarningService::NotifyWarningsOnUI( |
| 736 profile, warnings); |
| 737 if (winner_extension_id == determiners_[index].extension_id) |
| 738 determiner_ = determiners_[index]; |
714 } | 739 } |
715 break; | 740 break; |
716 } | 741 } |
717 } | 742 } |
718 if (!found_info) | 743 if (!found_info) |
719 return false; | 744 return false; |
720 CheckAllDeterminersCalled(); | 745 CheckAllDeterminersCalled(); |
721 return true; | 746 return true; |
722 } | 747 } |
723 | 748 |
(...skipping 827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1551 change.Run(data->creator_suggested_filename(), | 1576 change.Run(data->creator_suggested_filename(), |
1552 ConvertConflictAction(data->creator_conflict_action())); | 1577 ConvertConflictAction(data->creator_conflict_action())); |
1553 // If all listeners are removed, don't keep |data| around. | 1578 // If all listeners are removed, don't keep |data| around. |
1554 data->ResetCreatorSuggestion(); | 1579 data->ResetCreatorSuggestion(); |
1555 } else { | 1580 } else { |
1556 no_change.Run(); | 1581 no_change.Run(); |
1557 } | 1582 } |
1558 } | 1583 } |
1559 } | 1584 } |
1560 | 1585 |
| 1586 void ExtensionDownloadsEventRouter::DetermineFilenameInternal( |
| 1587 const base::FilePath& filename, |
| 1588 extensions::api::downloads::FilenameConflictAction conflict_action, |
| 1589 const std::string& suggesting_extension_id, |
| 1590 const base::Time& suggesting_install_time, |
| 1591 const std::string& incumbent_extension_id, |
| 1592 const base::Time& incumbent_install_time, |
| 1593 std::string* winner_extension_id, |
| 1594 base::FilePath* determined_filename, |
| 1595 extensions::api::downloads::FilenameConflictAction* |
| 1596 determined_conflict_action, |
| 1597 extensions::ExtensionWarningSet* warnings) { |
| 1598 DCHECK(!filename.empty()); |
| 1599 DCHECK(!suggesting_extension_id.empty()); |
| 1600 |
| 1601 if (incumbent_extension_id.empty()) { |
| 1602 *winner_extension_id = suggesting_extension_id; |
| 1603 *determined_filename = filename; |
| 1604 *determined_conflict_action = conflict_action; |
| 1605 return; |
| 1606 } |
| 1607 |
| 1608 if (suggesting_install_time < incumbent_install_time) { |
| 1609 *winner_extension_id = incumbent_extension_id; |
| 1610 warnings->insert( |
| 1611 extensions::ExtensionWarning::CreateDownloadFilenameConflictWarning( |
| 1612 suggesting_extension_id, |
| 1613 incumbent_extension_id, |
| 1614 filename, |
| 1615 *determined_filename)); |
| 1616 return; |
| 1617 } |
| 1618 |
| 1619 *winner_extension_id = suggesting_extension_id; |
| 1620 warnings->insert( |
| 1621 extensions::ExtensionWarning::CreateDownloadFilenameConflictWarning( |
| 1622 incumbent_extension_id, |
| 1623 suggesting_extension_id, |
| 1624 *determined_filename, |
| 1625 filename)); |
| 1626 *determined_filename = filename; |
| 1627 *determined_conflict_action = conflict_action; |
| 1628 } |
| 1629 |
1561 bool ExtensionDownloadsEventRouter::DetermineFilename( | 1630 bool ExtensionDownloadsEventRouter::DetermineFilename( |
1562 Profile* profile, | 1631 Profile* profile, |
1563 bool include_incognito, | 1632 bool include_incognito, |
1564 const std::string& ext_id, | 1633 const std::string& ext_id, |
1565 int download_id, | 1634 int download_id, |
1566 const base::FilePath& const_filename, | 1635 const base::FilePath& const_filename, |
1567 extensions::api::downloads::FilenameConflictAction conflict_action, | 1636 extensions::api::downloads::FilenameConflictAction conflict_action, |
1568 std::string* error) { | 1637 std::string* error) { |
1569 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1638 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1570 DownloadItem* item = GetDownload(profile, include_incognito, download_id); | 1639 DownloadItem* item = GetDownload(profile, include_incognito, download_id); |
(...skipping 13 matching lines...) Expand all Loading... |
1584 base::FilePath::StringType filename_str(const_filename.value()); | 1653 base::FilePath::StringType filename_str(const_filename.value()); |
1585 // Allow windows-style directory separators on all platforms. | 1654 // Allow windows-style directory separators on all platforms. |
1586 std::replace(filename_str.begin(), filename_str.end(), | 1655 std::replace(filename_str.begin(), filename_str.end(), |
1587 FILE_PATH_LITERAL('\\'), FILE_PATH_LITERAL('/')); | 1656 FILE_PATH_LITERAL('\\'), FILE_PATH_LITERAL('/')); |
1588 base::FilePath filename(filename_str); | 1657 base::FilePath filename(filename_str); |
1589 bool valid_filename = net::IsSafePortableRelativePath(filename); | 1658 bool valid_filename = net::IsSafePortableRelativePath(filename); |
1590 filename = (valid_filename ? filename.NormalizePathSeparators() : | 1659 filename = (valid_filename ? filename.NormalizePathSeparators() : |
1591 base::FilePath()); | 1660 base::FilePath()); |
1592 // If the invalid filename check is moved to before DeterminerCallback(), then | 1661 // If the invalid filename check is moved to before DeterminerCallback(), then |
1593 // it will block forever waiting for this ext_id to report. | 1662 // it will block forever waiting for this ext_id to report. |
1594 if (Fault(!data->DeterminerCallback(ext_id, filename, conflict_action), | 1663 if (Fault(!data->DeterminerCallback( |
| 1664 profile, ext_id, filename, conflict_action), |
1595 errors::kUnexpectedDeterminer, error) || | 1665 errors::kUnexpectedDeterminer, error) || |
1596 Fault((!const_filename.empty() && !valid_filename), | 1666 Fault((!const_filename.empty() && !valid_filename), |
1597 errors::kInvalidFilename, error)) | 1667 errors::kInvalidFilename, error)) |
1598 return false; | 1668 return false; |
1599 return true; | 1669 return true; |
1600 } | 1670 } |
1601 | 1671 |
1602 void ExtensionDownloadsEventRouter::OnListenerRemoved( | 1672 void ExtensionDownloadsEventRouter::OnListenerRemoved( |
1603 const extensions::EventListenerInfo& details) { | 1673 const extensions::EventListenerInfo& details) { |
1604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1674 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1783 content::NotificationService::current()->Notify( | 1853 content::NotificationService::current()->Notify( |
1784 chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT, | 1854 chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT, |
1785 content_source, | 1855 content_source, |
1786 content::Details<std::string>(&json_args)); | 1856 content::Details<std::string>(&json_args)); |
1787 } | 1857 } |
1788 | 1858 |
1789 void ExtensionDownloadsEventRouter::Observe( | 1859 void ExtensionDownloadsEventRouter::Observe( |
1790 int type, | 1860 int type, |
1791 const content::NotificationSource& source, | 1861 const content::NotificationSource& source, |
1792 const content::NotificationDetails& details) { | 1862 const content::NotificationDetails& details) { |
| 1863 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1793 switch (type) { | 1864 switch (type) { |
1794 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { | 1865 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { |
1795 extensions::UnloadedExtensionInfo* unloaded = | 1866 extensions::UnloadedExtensionInfo* unloaded = |
1796 content::Details<extensions::UnloadedExtensionInfo>(details).ptr(); | 1867 content::Details<extensions::UnloadedExtensionInfo>(details).ptr(); |
1797 std::set<const extensions::Extension*>::iterator iter = | 1868 std::set<const extensions::Extension*>::iterator iter = |
1798 shelf_disabling_extensions_.find(unloaded->extension); | 1869 shelf_disabling_extensions_.find(unloaded->extension); |
1799 if (iter != shelf_disabling_extensions_.end()) | 1870 if (iter != shelf_disabling_extensions_.end()) |
1800 shelf_disabling_extensions_.erase(iter); | 1871 shelf_disabling_extensions_.erase(iter); |
1801 break; | 1872 break; |
1802 } | 1873 } |
1803 } | 1874 } |
1804 } | 1875 } |
OLD | NEW |