summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorbauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-09 13:40:40 +0000
committerbauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-09 13:40:40 +0000
commit56f1a6ba817c77388d9df86c0f23db4dde7e0934 (patch)
treebd8c938c53f69f2ae1e104cf90cad49511e639b3 /chrome/browser
parent763e638fc941c4295feb961ea1c9b127de28de6a (diff)
downloadchromium_src-56f1a6ba817c77388d9df86c0f23db4dde7e0934.zip
chromium_src-56f1a6ba817c77388d9df86c0f23db4dde7e0934.tar.gz
chromium_src-56f1a6ba817c77388d9df86c0f23db4dde7e0934.tar.bz2
[Win] Add per-plugin exceptions to content settings.
Screenshot: http://imgur.com/yxEzO.png BUG=39252 TEST=PluginExceptionsTableModel.* Review URL: http://codereview.chromium.org/3307014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58929 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/host_content_settings_map.cc4
-rw-r--r--chrome/browser/plugin_exceptions_table_model.cc197
-rw-r--r--chrome/browser/plugin_exceptions_table_model.h78
-rw-r--r--chrome/browser/plugin_exceptions_table_model_unittest.cc190
-rw-r--r--chrome/browser/views/options/content_filter_page_view.cc24
5 files changed, 487 insertions, 6 deletions
diff --git a/chrome/browser/host_content_settings_map.cc b/chrome/browser/host_content_settings_map.cc
index 9c01798..c018219 100644
--- a/chrome/browser/host_content_settings_map.cc
+++ b/chrome/browser/host_content_settings_map.cc
@@ -489,8 +489,8 @@ void HostContentSettingsMap::SetContentSetting(
ContentSetting setting) {
DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- DCHECK(RequiresResourceIdentifier(content_type) !=
- resource_identifier.empty());
+ DCHECK_NE(RequiresResourceIdentifier(content_type),
+ resource_identifier.empty());
bool early_exit = false;
std::string pattern_str(pattern.AsString());
diff --git a/chrome/browser/plugin_exceptions_table_model.cc b/chrome/browser/plugin_exceptions_table_model.cc
new file mode 100644
index 0000000..f610432
--- /dev/null
+++ b/chrome/browser/plugin_exceptions_table_model.cc
@@ -0,0 +1,197 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/plugin_exceptions_table_model.h"
+
+#include "app/l10n_util.h"
+#include "app/table_model_observer.h"
+#include "base/auto_reset.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/notification_service.h"
+#include "grit/generated_resources.h"
+#include "webkit/glue/plugins/plugin_list.h"
+
+PluginExceptionsTableModel::PluginExceptionsTableModel(
+ HostContentSettingsMap* content_settings_map,
+ HostContentSettingsMap* otr_content_settings_map)
+ : map_(content_settings_map),
+ otr_map_(otr_content_settings_map),
+ updates_disabled_(false),
+ observer_(NULL) {
+ registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
+ NotificationService::AllSources());
+}
+
+bool PluginExceptionsTableModel::CanRemoveRows(const Rows& rows) const {
+ return !rows.empty();
+}
+
+void PluginExceptionsTableModel::RemoveRows(const Rows& rows) {
+ AutoReset<bool> tmp(&updates_disabled_, true);
+ bool reload_all = false;
+ // Iterate in reverse over the rows to get the indexes right.
+ for (Rows::const_reverse_iterator it = rows.rbegin();
+ it != rows.rend(); ++it) {
+ SettingsEntry& entry = settings_[*it];
+ HostContentSettingsMap* map = entry.is_otr ? otr_map_ : map_;
+ map->SetContentSetting(entry.pattern,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ resources_[entry.plugin_id],
+ CONTENT_SETTING_DEFAULT);
+ row_counts_[entry.plugin_id]--;
+ // If we remove the last exception for a plugin, recreate all groups to get
+ // correct IDs.
+ if (row_counts_[entry.plugin_id] == 0)
+ reload_all = true;
+ settings_.erase(settings_.begin() + *it);
+ }
+ if (reload_all) {
+ // This also notifies the observer.
+ ReloadSettings();
+ } else if (observer_) {
+ for (Rows::const_reverse_iterator it = rows.rbegin();
+ it != rows.rend(); ++it) {
+ observer_->OnItemsRemoved(*it, 1);
+ }
+ }
+}
+
+void PluginExceptionsTableModel::RemoveAll() {
+ int old_row_count = RowCount();
+ {
+ AutoReset<bool> tmp(&updates_disabled_, true);
+ map_->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS);
+ if (otr_map_)
+ otr_map_->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS);
+ }
+ ClearSettings();
+ if (observer_)
+ observer_->OnItemsRemoved(0, old_row_count);
+}
+
+int PluginExceptionsTableModel::RowCount() {
+ return settings_.size();
+}
+
+std::wstring PluginExceptionsTableModel::GetText(int row, int column_id) {
+ DCHECK_GE(row, 0);
+ DCHECK_LT(row, static_cast<int>(settings_.size()));
+ SettingsEntry& entry = settings_[row];
+ switch (column_id) {
+ case IDS_EXCEPTIONS_PATTERN_HEADER:
+ case IDS_EXCEPTIONS_HOSTNAME_HEADER:
+ return UTF8ToWide(entry.pattern.AsString());
+
+ case IDS_EXCEPTIONS_ACTION_HEADER:
+ switch (entry.setting) {
+ case CONTENT_SETTING_ALLOW:
+ return l10n_util::GetString(IDS_EXCEPTIONS_ALLOW_BUTTON);
+ case CONTENT_SETTING_BLOCK:
+ return l10n_util::GetString(IDS_EXCEPTIONS_BLOCK_BUTTON);
+ default:
+ NOTREACHED();
+ }
+ break;
+
+ default:
+ NOTREACHED();
+ }
+
+ return std::wstring();
+}
+
+void PluginExceptionsTableModel::SetObserver(TableModelObserver* observer) {
+ observer_ = observer;
+}
+
+TableModel::Groups PluginExceptionsTableModel::GetGroups() {
+ return groups_;
+}
+
+int PluginExceptionsTableModel::GetGroupID(int row) {
+ DCHECK_LT(row, static_cast<int>(settings_.size()));
+ return settings_[row].plugin_id;
+}
+
+void PluginExceptionsTableModel::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (!updates_disabled_)
+ ReloadSettings();
+}
+
+void PluginExceptionsTableModel::ClearSettings() {
+ settings_.clear();
+ groups_.clear();
+ row_counts_.clear();
+ resources_.clear();
+}
+
+void PluginExceptionsTableModel::GetPlugins(
+ std::vector<WebPluginInfo>* plugins) {
+ NPAPI::PluginList::Singleton()->GetPlugins(false, plugins);
+}
+
+void PluginExceptionsTableModel::LoadSettings() {
+ int group_id = 0;
+ std::vector<WebPluginInfo> plugins;
+ GetPlugins(&plugins);
+ for (std::vector<WebPluginInfo>::iterator it = plugins.begin();
+ it != plugins.end(); ++it) {
+#if defined OS_POSIX
+ std::string plugin = it->path.value();
+#elif defined OS_WIN
+ std::string plugin = base::SysWideToUTF8(it->path.value());
+#endif
+ HostContentSettingsMap::SettingsForOneType settings;
+ map_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ plugin,
+ &settings);
+ HostContentSettingsMap::SettingsForOneType otr_settings;
+ if (otr_map_) {
+ otr_map_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ plugin,
+ &otr_settings);
+ }
+ std::wstring title = UTF16ToWide(it->name);
+ for (HostContentSettingsMap::SettingsForOneType::iterator setting_it =
+ settings.begin(); setting_it != settings.end(); ++setting_it) {
+ SettingsEntry entry = {
+ setting_it->first,
+ group_id,
+ setting_it->second,
+ false
+ };
+ settings_.push_back(entry);
+ }
+ for (HostContentSettingsMap::SettingsForOneType::iterator setting_it =
+ otr_settings.begin();
+ setting_it != otr_settings.end(); ++setting_it) {
+ SettingsEntry entry = {
+ setting_it->first,
+ group_id,
+ setting_it->second,
+ true
+ };
+ settings_.push_back(entry);
+ }
+ int num_plugins = settings.size() + otr_settings.size();
+ if (num_plugins > 0) {
+ Group group = { title, group_id++ };
+ groups_.push_back(group);
+ resources_.push_back(plugin);
+ row_counts_.push_back(num_plugins);
+ }
+ }
+}
+
+void PluginExceptionsTableModel::ReloadSettings() {
+ ClearSettings();
+ LoadSettings();
+
+ if (observer_)
+ observer_->OnModelChanged();
+}
+
diff --git a/chrome/browser/plugin_exceptions_table_model.h b/chrome/browser/plugin_exceptions_table_model.h
new file mode 100644
index 0000000..8732a0d
--- /dev/null
+++ b/chrome/browser/plugin_exceptions_table_model.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PLUGIN_EXCEPTIONS_TABLE_MODEL_H_
+#define CHROME_BROWSER_PLUGIN_EXCEPTIONS_TABLE_MODEL_H_
+#pragma once
+
+#include <deque>
+
+#include "chrome/browser/remove_rows_table_model.h"
+#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/common/notification_observer.h"
+
+struct WebPluginInfo;
+
+class PluginExceptionsTableModel : public RemoveRowsTableModel,
+ public NotificationObserver {
+ public:
+ PluginExceptionsTableModel(HostContentSettingsMap* content_settings_map,
+ HostContentSettingsMap* otr_content_settings_map);
+ virtual ~PluginExceptionsTableModel() {}
+
+ // Load plugin exceptions from the HostContentSettingsMaps. You should call
+ // this method after creating a new PluginExceptionsTableModel.
+ void LoadSettings();
+
+ // RemoveRowsTableModel methods:
+ virtual bool CanRemoveRows(const Rows& rows) const;
+ virtual void RemoveRows(const Rows& rows);
+ virtual void RemoveAll();
+
+ // TableModel methods:
+ virtual int RowCount();
+ virtual std::wstring GetText(int row, int column_id);
+ virtual void SetObserver(TableModelObserver* observer);
+ virtual bool HasGroups() { return true; }
+ virtual Groups GetGroups();
+ virtual int GetGroupID(int row);
+
+ // NotificationObserver methods:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ protected:
+ // Subclasses can override this method for testing.
+ virtual void GetPlugins(std::vector<WebPluginInfo>* plugins);
+
+ private:
+ friend class PluginExceptionsTableModelTest;
+
+ struct SettingsEntry {
+ HostContentSettingsMap::Pattern pattern;
+ int plugin_id;
+ ContentSetting setting;
+ bool is_otr;
+ };
+
+ void ClearSettings();
+ void ReloadSettings();
+
+ HostContentSettingsMap* map_;
+ HostContentSettingsMap* otr_map_;
+
+ std::deque<SettingsEntry> settings_;
+ std::deque<int> row_counts_;
+ std::deque<std::string> resources_;
+ TableModel::Groups groups_;
+
+ NotificationRegistrar registrar_;
+ bool updates_disabled_;
+ TableModelObserver* observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginExceptionsTableModel);
+};
+
+#endif // CHROME_BROWSER_PLUGIN_EXCEPTIONS_TABLE_MODEL_H_
diff --git a/chrome/browser/plugin_exceptions_table_model_unittest.cc b/chrome/browser/plugin_exceptions_table_model_unittest.cc
new file mode 100644
index 0000000..09eac8a
--- /dev/null
+++ b/chrome/browser/plugin_exceptions_table_model_unittest.cc
@@ -0,0 +1,190 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "app/table_model_observer.h"
+#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/plugin_exceptions_table_model.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_pref_service.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/glue/plugins/webplugininfo.h"
+
+namespace {
+
+class MockTableModelObserver : public TableModelObserver {
+ public:
+ MOCK_METHOD0(OnModelChanged, void());
+ MOCK_METHOD2(OnItemsChanged, void(int start, int length));
+ MOCK_METHOD2(OnItemsAdded, void(int start, int length));
+ MOCK_METHOD2(OnItemsRemoved, void(int start, int length));
+};
+
+class TestingPluginExceptionsTableModel : public PluginExceptionsTableModel {
+ public:
+ TestingPluginExceptionsTableModel(HostContentSettingsMap* map,
+ HostContentSettingsMap* otr_map)
+ : PluginExceptionsTableModel(map, otr_map) {}
+ virtual ~TestingPluginExceptionsTableModel() {}
+
+ void set_plugins(const std::vector<WebPluginInfo>& plugins) {
+ plugins_ = plugins;
+ }
+
+ protected:
+ virtual void GetPlugins(std::vector<WebPluginInfo>* plugins) {
+ *plugins = plugins_;
+ }
+
+ private:
+ std::vector<WebPluginInfo> plugins_;
+};
+
+}
+
+class PluginExceptionsTableModelTest : public testing::Test {
+ public:
+ PluginExceptionsTableModelTest()
+ : ui_thread_(ChromeThread::UI, &message_loop_),
+ command_line_(*CommandLine::ForCurrentProcess()) {}
+
+ virtual void SetUp() {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableResourceContentSettings);
+
+ profile_.reset(new TestingProfile());
+
+ HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
+
+ HostContentSettingsMap::Pattern example_com("[*.]example.com");
+ HostContentSettingsMap::Pattern moose_org("[*.]moose.org");
+ map->SetContentSetting(example_com,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ "foo",
+ CONTENT_SETTING_ALLOW);
+ map->SetContentSetting(moose_org,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ "bar",
+ CONTENT_SETTING_BLOCK);
+ map->SetContentSetting(example_com,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ "bar",
+ CONTENT_SETTING_ALLOW);
+
+ table_model_.reset(new TestingPluginExceptionsTableModel(
+ map,
+ NULL));
+
+ std::vector<WebPluginInfo> plugins;
+ WebPluginInfo foo_plugin;
+ foo_plugin.path = FilePath(FILE_PATH_LITERAL("foo"));
+ foo_plugin.name = ASCIIToUTF16("FooPlugin");
+ foo_plugin.enabled = true;
+ plugins.push_back(foo_plugin);
+ WebPluginInfo bar_plugin;
+ bar_plugin.path = FilePath(FILE_PATH_LITERAL("bar"));
+ bar_plugin.name = ASCIIToUTF16("BarPlugin");
+ bar_plugin.enabled = true;
+ plugins.push_back(bar_plugin);
+
+ table_model_->set_plugins(plugins);
+ table_model_->ReloadSettings();
+ }
+
+ virtual void TearDown() {
+ *CommandLine::ForCurrentProcess() = command_line_;
+ }
+
+ protected:
+ void CheckInvariants() {
+ typedef std::deque<PluginExceptionsTableModel::SettingsEntry> Entries;
+ Entries& settings = table_model_->settings_;
+ std::deque<int>& row_counts = table_model_->row_counts_;
+ std::deque<std::string>& resources = table_model_->resources_;
+ TableModel::Groups& groups = table_model_->groups_;
+
+ EXPECT_EQ(groups.size(), row_counts.size());
+ EXPECT_EQ(groups.size(), resources.size());
+
+ int last_plugin = 0;
+ int count = 0;
+ for (Entries::const_iterator it = settings.begin();
+ it != settings.end(); ++it) {
+ // Plugin IDs are indices into |groups|.
+ EXPECT_GE(it->plugin_id, 0);
+ EXPECT_LT(it->plugin_id, static_cast<int>(groups.size()));
+ if (it->plugin_id == last_plugin) {
+ count++;
+ } else {
+ // Plugin IDs are ascending one by one.
+ EXPECT_EQ(last_plugin+1, it->plugin_id);
+
+ // Consecutive runs of plugins with id |x| are |row_counts[x]| long.
+ EXPECT_EQ(count, row_counts[last_plugin]);
+ count = 1;
+ last_plugin = it->plugin_id;
+ }
+ }
+ if (row_counts.size() > 0)
+ EXPECT_EQ(count, row_counts[last_plugin]);
+ }
+
+ protected:
+ MessageLoop message_loop_;
+ ChromeThread ui_thread_;
+
+ scoped_ptr<TestingProfile> profile_;
+ scoped_ptr<TestingPluginExceptionsTableModel> table_model_;
+
+ private:
+ CommandLine command_line_;
+};
+
+TEST_F(PluginExceptionsTableModelTest, Basic) {
+ EXPECT_EQ(3, table_model_->RowCount());
+ CheckInvariants();
+}
+
+TEST_F(PluginExceptionsTableModelTest, RemoveOneRow) {
+ MockTableModelObserver observer;
+ table_model_->SetObserver(&observer);
+
+ EXPECT_CALL(observer, OnItemsRemoved(1, 1));
+ RemoveRowsTableModel::Rows rows;
+ rows.insert(1);
+ table_model_->RemoveRows(rows);
+ EXPECT_EQ(2, table_model_->RowCount());
+ EXPECT_EQ(2, static_cast<int>(table_model_->GetGroups().size()));
+ CheckInvariants();
+ table_model_->SetObserver(NULL);
+}
+
+TEST_F(PluginExceptionsTableModelTest, RemoveLastRowInGroup) {
+ MockTableModelObserver observer;
+ table_model_->SetObserver(&observer);
+
+ EXPECT_CALL(observer, OnModelChanged());
+ RemoveRowsTableModel::Rows rows;
+ rows.insert(0);
+ table_model_->RemoveRows(rows);
+ EXPECT_EQ(2, table_model_->RowCount());
+ EXPECT_EQ(1, static_cast<int>(table_model_->GetGroups().size()));
+ CheckInvariants();
+ table_model_->SetObserver(NULL);
+}
+
+TEST_F(PluginExceptionsTableModelTest, RemoveAllRows) {
+ MockTableModelObserver observer;
+ table_model_->SetObserver(&observer);
+
+ EXPECT_CALL(observer, OnItemsRemoved(0, 3));
+ table_model_->RemoveAll();
+ EXPECT_EQ(0, table_model_->RowCount());
+ EXPECT_EQ(0, static_cast<int>(table_model_->GetGroups().size()));
+ CheckInvariants();
+ table_model_->SetObserver(NULL);
+}
diff --git a/chrome/browser/views/options/content_filter_page_view.cc b/chrome/browser/views/options/content_filter_page_view.cc
index c017558..ac2ab38 100644
--- a/chrome/browser/views/options/content_filter_page_view.cc
+++ b/chrome/browser/views/options/content_filter_page_view.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/geolocation/geolocation_exceptions_table_model.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification_exceptions_table_model.h"
+#include "chrome/browser/plugin_exceptions_table_model.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/options/exceptions_view.h"
#include "chrome/browser/views/options/simple_content_exceptions_view.h"
@@ -190,12 +191,27 @@ void ContentFilterPageView::ButtonPressed(views::Button* sender,
profile()->GetDesktopNotificationService()),
IDS_NOTIFICATIONS_EXCEPTION_TITLE);
} else {
- ExceptionsView::ShowExceptionsWindow(GetWindow()->GetNativeWindow(),
- profile()->GetHostContentSettingsMap(),
+ HostContentSettingsMap* settings = profile()->GetHostContentSettingsMap();
+ HostContentSettingsMap* otr_settings =
profile()->HasOffTheRecordProfile() ?
profile()->GetOffTheRecordProfile()->GetHostContentSettingsMap() :
- NULL,
- content_type_);
+ NULL;
+ if (content_type_ == CONTENT_SETTINGS_TYPE_PLUGINS &&
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableResourceContentSettings)) {
+ PluginExceptionsTableModel* model =
+ new PluginExceptionsTableModel(settings, otr_settings);
+ model->LoadSettings();
+ SimpleContentExceptionsView::ShowExceptionsWindow(
+ GetWindow()->GetNativeWindow(),
+ model,
+ IDS_PLUGINS_EXCEPTION_TITLE);
+ } else {
+ ExceptionsView::ShowExceptionsWindow(GetWindow()->GetNativeWindow(),
+ settings,
+ otr_settings,
+ content_type_);
+ }
}
return;
}