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

Side by Side Diff: chrome/browser/extensions/api/downloads/downloads_api.cc

Issue 22612003: Warn when extensions suggest conflicting download filenames (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: @r216682 Created 7 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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698