diff options
author | gspencer@chromium.org <gspencer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-14 23:59:26 +0000 |
---|---|---|
committer | gspencer@chromium.org <gspencer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-14 23:59:26 +0000 |
commit | 6fdd418b9a50f24f7788e229bd3ae4acaf6ec1d4 (patch) | |
tree | d55a82a8551a7df61d6c84f13835e7b8e17507f3 /chrome/browser | |
parent | 6f7582fd31ff06faa0298ab6d530369256e9f20a (diff) | |
download | chromium_src-6fdd418b9a50f24f7788e229bd3ae4acaf6ec1d4.zip chromium_src-6fdd418b9a50f24f7788e229bd3ae4acaf6ec1d4.tar.gz chromium_src-6fdd418b9a50f24f7788e229bd3ae4acaf6ec1d4.tar.bz2 |
This adds a plugin selection policy for selecting which plugin is
allowed for a particular domain.
It is only used on ChromeOS. It reads from a file that is installed
in a known location on ChromeOS, and uses that as it's policy.
When there are multiple plugins supporting the same mime-type, the
appropriate plugin file to load is now selected based on policy.
BUG=http://crosbug.com/7403
TEST=ran new unit test, tested on device.
Review URL: http://codereview.chromium.org/3717005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62679 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/chromeos/plugin_selection_policy.cc | 166 | ||||
-rw-r--r-- | chrome/browser/chromeos/plugin_selection_policy.h | 79 | ||||
-rw-r--r-- | chrome/browser/chromeos/plugin_selection_policy_unittest.cc | 270 | ||||
-rw-r--r-- | chrome/browser/plugin_service.cc | 80 | ||||
-rw-r--r-- | chrome/browser/plugin_service.h | 38 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 76 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 19 |
7 files changed, 670 insertions, 58 deletions
diff --git a/chrome/browser/chromeos/plugin_selection_policy.cc b/chrome/browser/chromeos/plugin_selection_policy.cc new file mode 100644 index 0000000..b27bc42 --- /dev/null +++ b/chrome/browser/chromeos/plugin_selection_policy.cc @@ -0,0 +1,166 @@ +// 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/chromeos/plugin_selection_policy.h" + +#include <algorithm> +#include <iostream> +#include <map> +#include <sstream> +#include <string> +#include <vector> + +#include "base/auto_reset.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "chrome/browser/browser_thread.h" +#include "googleurl/src/gurl.h" + +#if !defined(OS_CHROMEOS) +#error This file is meant to be compiled on ChromeOS only. +#endif + +using std::vector; +using std::string; +using std::pair; +using std::map; + +namespace chromeos { + +static const char kPluginSelectionPolicyFile[] = + "/usr/share/chromeos-assets/flash/plugin_policy"; + +PluginSelectionPolicy::PluginSelectionPolicy() : initialized_(false) { +} + +void PluginSelectionPolicy::StartInit() { + // Initialize the policy on the FILE thread, since it reads from a + // policy file. + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod(this, &chromeos::PluginSelectionPolicy::Init)); +} + +bool PluginSelectionPolicy::Init() { + return InitFromFile(FilePath(kPluginSelectionPolicyFile)); +} + +bool PluginSelectionPolicy::InitFromFile(const FilePath& policy_file) { + // This must always be called from the FILE thread. + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + // Note: We're "initialized" even if loading the file fails. + initialized_ = true; + + string data; + // This should be a really small file, so we're OK with just + // slurping it. + if (!file_util::ReadFileToString(policy_file, &data)) { + LOG(ERROR) << "Unable to read plugin policy file \"" + << policy_file.value() << "\"."; + return false; + } + + std::istringstream input_stream(data); + string line; + map<string, Policy> policies; + Policy policy; + string last_plugin; + + while (std::getline(input_stream, line)) { + // Strip comments. + string::size_type pos = line.find("#"); + if (pos != string::npos) { + line = line.substr(0, pos); + } + TrimWhitespaceASCII(line, TRIM_ALL, &line); + if (line.find("allow") == 0) { + // Has to be preceeded by a "plugin" statement. + if (last_plugin.empty()) { + LOG(ERROR) << "Plugin policy file error: 'allow' out of context."; + return false; + } + line = line.substr(6); + TrimWhitespaceASCII(line, TRIM_ALL, &line); + line = StringToLowerASCII(line); + policy.push_back(make_pair(true, line)); + } + if (line.find("deny") == 0) { + // Has to be preceeded by a "plugin" statement. + if (last_plugin.empty()) { + LOG(ERROR) << "Plugin policy file error: 'deny' out of context."; + return false; + } + line = line.substr(5); + TrimWhitespaceASCII(line, TRIM_ALL, &line); + line = StringToLowerASCII(line); + policy.push_back(make_pair(false, line)); + } + if (line.find("plugin") == 0) { + line = line.substr(7); + TrimWhitespaceASCII(line, TRIM_ALL, &line); + if (!policy.empty() && !last_plugin.empty()) + policies.insert(make_pair(last_plugin, policy)); + last_plugin = line; + policy.clear(); + } + } + + if (!last_plugin.empty()) + policies.insert(make_pair(last_plugin, policy)); + + policies_.swap(policies); + return true; +} + +int PluginSelectionPolicy::FindFirstAllowed( + const GURL& url, + const std::vector<WebPluginInfo>& info) { + for (std::vector<WebPluginInfo>::size_type i = 0; i < info.size(); ++i) { + if (IsAllowed(url, info[i].path)) + return i; + } + return -1; +} + +bool PluginSelectionPolicy::IsAllowed(const GURL& url, + const FilePath& path) { + // This must always be called from the FILE thread, to be sure + // initialization doesn't happen at the same time. + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + // Make sure that we notice if this starts being called before + // initialization is complete. Right now it is guaranteed only by + // the startup order and the fact that InitFromFile runs on the FILE + // thread too. + DCHECK(initialized_) << "Tried to check policy before policy is initialized."; + + string name = path.BaseName().value(); + + PolicyMap::iterator policy_iter = policies_.find(name); + if (policy_iter != policies_.end()) { + Policy& policy(policy_iter->second); + + // We deny by default. (equivalent to "deny" at the top of the section) + bool allow = false; + + for (Policy::iterator iter = policy.begin(); iter != policy.end(); ++iter) { + bool policy_allow = iter->first; + string& policy_domain = iter->second; + if (policy_domain.empty() || url.DomainIs(policy_domain.c_str(), + policy_domain.size())) { + allow = policy_allow; + } + } + return allow; + } + + // If it's not in the policy file, then we assume it's OK to allow + // it. + return true; +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/plugin_selection_policy.h b/chrome/browser/chromeos/plugin_selection_policy.h new file mode 100644 index 0000000..4786e3c --- /dev/null +++ b/chrome/browser/chromeos/plugin_selection_policy.h @@ -0,0 +1,79 @@ +// 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_CHROMEOS_PLUGIN_SELECTION_POLICY_H_ +#define CHROME_BROWSER_CHROMEOS_PLUGIN_SELECTION_POLICY_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/gtest_prod_util.h" +#include "base/ref_counted.h" +#include "webkit/glue/plugins/webplugininfo.h" + +class GURL; +class FilePath; + +namespace chromeos { + +#if !defined(OS_CHROMEOS) +#error This file is meant to be compiled on ChromeOS only. +#endif + +// This class is used to provide logic for selection of a plugin +// executable path in the browser. It loads a policy file for +// selection of particular plugins based on the domain they are be +// instantiated for. It is used by the PluginService. It is (and +// should be) only used for ChromeOS. + +// The functions in this class must only be called on the FILE thread +// (and will DCHECK if they aren't). + +class PluginSelectionPolicy + : public base::RefCountedThreadSafe<PluginSelectionPolicy> { + public: + PluginSelectionPolicy(); + + // This should be called before any other method. This starts the + // process of initialization on the FILE thread. + void StartInit(); + + // Returns the first allowed plugin in the given vector of plugin + // information. Returns -1 if no plugins in the info vector are + // allowed (or if the info vector is empty). InitFromFile must + // complete before any calls to FindFirstAllowed happen or it will + // assert. + int FindFirstAllowed(const GURL& url, const std::vector<WebPluginInfo>& info); + + // Applies the current policy to the given path using the url to + // look up what the policy for that domain is. Returns true if the + // given plugin is allowed for that domain. InitFromFile must + // complete before any calls to IsAllowed happen or it will assert. + bool IsAllowed(const GURL& url, const FilePath& path); + + private: + // To allow access to InitFromFile + FRIEND_TEST_ALL_PREFIXES(PluginSelectionPolicyTest, Basic); + FRIEND_TEST_ALL_PREFIXES(PluginSelectionPolicyTest, InitFromFile); + FRIEND_TEST_ALL_PREFIXES(PluginSelectionPolicyTest, IsAllowed); + FRIEND_TEST_ALL_PREFIXES(PluginSelectionPolicyTest, FindFirstAllowed); + + // Initializes from the default policy file. + bool Init(); + + // Initializes from the given file. + bool InitFromFile(const FilePath& policy_file); + + typedef std::vector<std::pair<bool, std::string> > Policy; + typedef std::map<std::string, Policy> PolicyMap; + + PolicyMap policies_; + bool initialized_; + + DISALLOW_COPY_AND_ASSIGN(PluginSelectionPolicy); +}; + +} // namespace chromeos +#endif // CHROME_BROWSER_CHROMEOS_PLUGIN_SELECTION_POLICY_H_ diff --git a/chrome/browser/chromeos/plugin_selection_policy_unittest.cc b/chrome/browser/chromeos/plugin_selection_policy_unittest.cc new file mode 100644 index 0000000..455ed37 --- /dev/null +++ b/chrome/browser/chromeos/plugin_selection_policy_unittest.cc @@ -0,0 +1,270 @@ +// 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/chromeos/plugin_selection_policy.h" + +#include <string> +#include <vector> + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/ref_counted.h" +#include "base/scoped_temp_dir.h" +#include "chrome/browser/browser_thread.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +using std::string; +using std::vector; + +#if !defined(OS_CHROMEOS) +#error This file is meant to be compiled on ChromeOS only. +#endif + +namespace chromeos { + +const char kBasicPolicy[] = "# This is a basic policy\n" + "plugin test.so\n" + "allow foo.com\n" + "deny bar.com\n"; + +const char kNoPluginPolicy[] = "# This is a policy with missing plugin.\n" + "# Missing plugin test.so\n" + "allow foo.com\n" + "deny bar.com\n"; +const char kNoRulesPolicy[] = "# This is a policy with no rules\n" + "plugin test.so\n"; + +const char kEmptyPolicy[] = "# This is an empty policy\n"; + +const char kCommentTestPolicy[] = "# This is a policy with inline comments.\n" + "plugin test.so# like this\n" + "allow foo.com # and this\n" + "deny bar.com # and this\n"; + +const char kMultiPluginTestPolicy[] = + "# This is a policy with multiple plugins.\n" + "plugin allow_foo.so\n" + "allow foo.com\n" + "deny bar.com\n" + "plugin allow_baz_bim1.so\n" + "deny google.com\n" + "allow baz.com\n" + "allow bim.com\n" + "plugin allow_baz_bim2.so\n" + "deny google.com\n" + "allow baz.com\n" + "allow bim.com\n"; + +const char kWhitespaceTestPolicy[] = "# This is a policy with odd whitespace.\n" + " plugin\ttest.so# like this\n" + "\n\n \n allow\t\tfoo.com # and this\n" + "\tdeny bar.com\t\t\t# and this \n"; + +class PluginSelectionPolicyTest : public PlatformTest { + public: + PluginSelectionPolicyTest() + : loop_(MessageLoop::TYPE_DEFAULT), + file_thread_(BrowserThread::FILE, &loop_) {} + + virtual void SetUp() { + PlatformTest::SetUp(); + // Create a policy file to test with. + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + } + + protected: + bool CreatePolicy(const std::string& name, + const std::string& contents, + FilePath* path) { + FilePath policy_file(temp_dir_.path()); + policy_file = policy_file.Append(FilePath(name)); + int bytes_written = file_util::WriteFile(policy_file, + contents.c_str(), + contents.size()); + if (path) + *path = policy_file; + return bytes_written >= 0; + } + + private: + ScopedTempDir temp_dir_; + MessageLoop loop_; + BrowserThread file_thread_; +}; + +TEST_F(PluginSelectionPolicyTest, Basic) { + FilePath path; + ASSERT_TRUE(CreatePolicy("basic", kBasicPolicy, &path)); + scoped_refptr<PluginSelectionPolicy> policy = new PluginSelectionPolicy; + EXPECT_TRUE(policy->InitFromFile(path)); +} + +TEST_F(PluginSelectionPolicyTest, InitFromFile) { + { + FilePath path; + ASSERT_TRUE(CreatePolicy("basic", kBasicPolicy, &path)); + scoped_refptr<PluginSelectionPolicy> policy = new PluginSelectionPolicy; + EXPECT_TRUE(policy->InitFromFile(path)); + } + + { + FilePath path; + ASSERT_TRUE(CreatePolicy("no_plugin", kNoPluginPolicy, &path)); + scoped_refptr<PluginSelectionPolicy> policy = new PluginSelectionPolicy; + EXPECT_FALSE(policy->InitFromFile(path)); + } + + { + FilePath path; + ASSERT_TRUE(CreatePolicy("no_rules", kNoRulesPolicy, &path)); + scoped_refptr<PluginSelectionPolicy> policy = new PluginSelectionPolicy; + EXPECT_TRUE(policy->InitFromFile(path)); + } + + { + FilePath path; + ASSERT_TRUE(CreatePolicy("empty", kEmptyPolicy, &path)); + scoped_refptr<PluginSelectionPolicy> policy = new PluginSelectionPolicy; + EXPECT_TRUE(policy->InitFromFile(path)); + } + + { + FilePath path; + ASSERT_TRUE(CreatePolicy("comment", kCommentTestPolicy, &path)); + scoped_refptr<PluginSelectionPolicy> policy = new PluginSelectionPolicy; + EXPECT_TRUE(policy->InitFromFile(path)); + } + + { + FilePath path; + ASSERT_TRUE(CreatePolicy("comment", kMultiPluginTestPolicy, &path)); + scoped_refptr<PluginSelectionPolicy> policy = new PluginSelectionPolicy; + EXPECT_TRUE(policy->InitFromFile(path)); + } + + { + FilePath path; + ASSERT_TRUE(CreatePolicy("whitespace", kWhitespaceTestPolicy, &path)); + scoped_refptr<PluginSelectionPolicy> policy = new PluginSelectionPolicy; + EXPECT_TRUE(policy->InitFromFile(path)); + } +} + +TEST_F(PluginSelectionPolicyTest, IsAllowed) { + FilePath path; + ASSERT_TRUE(CreatePolicy("basic", kBasicPolicy, &path)); + + scoped_refptr<PluginSelectionPolicy> policy1 = new PluginSelectionPolicy; + ASSERT_TRUE(policy1->InitFromFile(path)); + EXPECT_TRUE(policy1->IsAllowed(GURL("http://www.foo.com/blah.html"), + FilePath("/usr/local/bin/test.so"))); + EXPECT_FALSE(policy1->IsAllowed(GURL("http://www.bar.com/blah.html"), + FilePath("/usr/local/bin/test.so"))); + EXPECT_FALSE(policy1->IsAllowed(GURL("http://www.baz.com/blah.html"), + FilePath("/usr/local/bin/test.so"))); + EXPECT_TRUE(policy1->IsAllowed(GURL("http://www.baz.com/blah.html"), + FilePath("/usr/local/bin/real.so"))); + + scoped_refptr<PluginSelectionPolicy> policy2 = new PluginSelectionPolicy; + ASSERT_TRUE(CreatePolicy("no_rules", kNoRulesPolicy, &path)); + ASSERT_TRUE(policy2->InitFromFile(path)); + EXPECT_FALSE(policy2->IsAllowed(GURL("http://www.foo.com/blah.html"), + FilePath("/usr/local/bin/test.so"))); + EXPECT_FALSE(policy2->IsAllowed(GURL("http://www.bar.com/blah.html"), + FilePath("/usr/local/bin/test.so"))); + EXPECT_FALSE(policy2->IsAllowed(GURL("http://www.baz.com/blah.html"), + FilePath("/usr/local/bin/test.so"))); + EXPECT_TRUE(policy2->IsAllowed(GURL("http://www.baz.com/blah.html"), + FilePath("/usr/local/bin/real.so"))); + + scoped_refptr<PluginSelectionPolicy> policy3 = new PluginSelectionPolicy; + ASSERT_TRUE(CreatePolicy("empty", kEmptyPolicy, &path)); + ASSERT_TRUE(policy3->InitFromFile(path)); + EXPECT_TRUE(policy3->IsAllowed(GURL("http://www.foo.com/blah.html"), + FilePath("/usr/local/bin/test.so"))); + EXPECT_TRUE(policy3->IsAllowed(GURL("http://www.bar.com/blah.html"), + FilePath("/usr/local/bin/test.so"))); + EXPECT_TRUE(policy3->IsAllowed(GURL("http://www.baz.com/blah.html"), + FilePath("/usr/local/bin/test.so"))); + EXPECT_TRUE(policy3->IsAllowed(GURL("http://www.baz.com/blah.html"), + FilePath("/usr/local/bin/real.so"))); +} + +TEST_F(PluginSelectionPolicyTest, FindFirstAllowed) { + FilePath path; + ASSERT_TRUE(CreatePolicy("multi", kMultiPluginTestPolicy, &path)); + scoped_refptr<PluginSelectionPolicy> policy = new PluginSelectionPolicy; + ASSERT_TRUE(policy->InitFromFile(path)); + EXPECT_TRUE(policy->IsAllowed(GURL("http://www.foo.com/blah.html"), + FilePath("/usr/local/bin/allow_foo.so"))); + EXPECT_FALSE(policy->IsAllowed(GURL("http://www.bar.com/blah.html"), + FilePath("/usr/local/bin/allow_foo.so"))); + EXPECT_FALSE(policy->IsAllowed(GURL("http://www.baz.com/blah.html"), + FilePath("/usr/local/bin/allow_foo.so"))); + EXPECT_FALSE(policy->IsAllowed(GURL("http://www.bim.com/blah.html"), + FilePath("/usr/local/bin/allow_foo.so"))); + EXPECT_FALSE(policy->IsAllowed(GURL("http://www.foo.com/blah.html"), + FilePath("/usr/local/bin/allow_baz_bim1.so"))); + EXPECT_FALSE(policy->IsAllowed(GURL("http://www.bar.com/blah.html"), + FilePath("/usr/local/bin/allow_baz_bim1.so"))); + EXPECT_TRUE(policy->IsAllowed(GURL("http://www.baz.com/blah.html"), + FilePath("/usr/local/bin/allow_baz_bim1.so"))); + EXPECT_TRUE(policy->IsAllowed(GURL("http://www.bim.com/blah.html"), + FilePath("/usr/local/bin/allow_baz_bim1.so"))); + EXPECT_FALSE(policy->IsAllowed(GURL("http://www.google.com/blah.html"), + FilePath("/usr/local/bin/allow_baz_bim1.so"))); + EXPECT_FALSE(policy->IsAllowed(GURL("http://www.foo.com/blah.html"), + FilePath("/usr/local/bin/allow_baz_bim2.so"))); + EXPECT_FALSE(policy->IsAllowed(GURL("http://www.bar.com/blah.html"), + FilePath("/usr/local/bin/allow_baz_bim2.so"))); + EXPECT_TRUE(policy->IsAllowed(GURL("http://www.baz.com/blah.html"), + FilePath("/usr/local/bin/allow_baz_bim2.so"))); + EXPECT_TRUE(policy->IsAllowed(GURL("http://www.bim.com/blah.html"), + FilePath("/usr/local/bin/allow_baz_bim2.so"))); + EXPECT_FALSE(policy->IsAllowed(GURL("http://www.google.com/blah.html"), + FilePath("/usr/local/bin/allow_baz_bim2.so"))); + std::vector<WebPluginInfo> info_vector; + WebPluginInfo info; + // First we test that the one without any policy gets + // selected for all if it's first. + info.path = FilePath("/usr/local/bin/no_policy.so"); + info_vector.push_back(info); + info.path = FilePath("/usr/local/bin/allow_foo.so"); + info_vector.push_back(info); + info.path = FilePath("/usr/local/bin/allow_baz_bim1.so"); + info_vector.push_back(info); + info.path = FilePath("/usr/local/bin/allow_baz_bim2.so"); + info_vector.push_back(info); + EXPECT_EQ(0, policy->FindFirstAllowed(GURL("http://www.baz.com/blah.html"), + info_vector)); + EXPECT_EQ(0, policy->FindFirstAllowed(GURL("http://www.foo.com/blah.html"), + info_vector)); + EXPECT_EQ(0, policy->FindFirstAllowed(GURL("http://www.bling.com/blah.html"), + info_vector)); + EXPECT_EQ(0, policy->FindFirstAllowed(GURL("http://www.google.com/blah.html"), + info_vector)); + + // Now move the plugin without any policy to the end. + info_vector.clear(); + info.path = FilePath("/usr/local/bin/allow_foo.so"); + info_vector.push_back(info); + info.path = FilePath("/usr/local/bin/allow_baz_bim1.so"); + info_vector.push_back(info); + info.path = FilePath("/usr/local/bin/allow_baz_bim2.so"); + info_vector.push_back(info); + info.path = FilePath("/usr/local/bin/no_policy.so"); + info_vector.push_back(info); + EXPECT_EQ(1, policy->FindFirstAllowed(GURL("http://www.baz.com/blah.html"), + info_vector)); + EXPECT_EQ(0, policy->FindFirstAllowed(GURL("http://www.foo.com/blah.html"), + info_vector)); + EXPECT_EQ(3, policy->FindFirstAllowed(GURL("http://www.bling.com/blah.html"), + info_vector)); + EXPECT_EQ(3, policy->FindFirstAllowed(GURL("http://www.google.com/blah.html"), + info_vector)); +} + +} // namespace chromeos diff --git a/chrome/browser/plugin_service.cc b/chrome/browser/plugin_service.cc index ebf4338..5f86020 100644 --- a/chrome/browser/plugin_service.cc +++ b/chrome/browser/plugin_service.cc @@ -40,6 +40,11 @@ #endif #include "webkit/glue/plugins/plugin_constants_win.h" #include "webkit/glue/plugins/plugin_list.h" +#include "webkit/glue/plugins/webplugininfo.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/plugin_selection_policy.h" +#endif #if defined(OS_MACOSX) static void NotifyPluginsOfActivation() { @@ -123,6 +128,11 @@ PluginService::PluginService() } #endif +#if defined(OS_CHROMEOS) + plugin_selection_policy_ = new chromeos::PluginSelectionPolicy; + plugin_selection_policy_->StartInit(); +#endif + chrome::RegisterInternalGPUPlugin(); #if defined(OS_WIN) @@ -243,17 +253,42 @@ void PluginService::OpenChannelToPlugin( ResourceMessageFilter* renderer_msg_filter, const GURL& url, const std::string& mime_type, - const std::string& locale, IPC::Message* reply_msg) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + // The PluginList::GetFirstAllowedPluginInfo may need to load the + // plugins. Don't do it on the IO thread. + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod( + this, &PluginService::GetAllowedPluginForOpenChannelToPlugin, + renderer_msg_filter, url, mime_type, reply_msg)); +} - bool allow_wildcard = true; +void PluginService::GetAllowedPluginForOpenChannelToPlugin( + ResourceMessageFilter* renderer_msg_filter, + const GURL& url, + const std::string& mime_type, + IPC::Message* reply_msg) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); WebPluginInfo info; + bool found = GetFirstAllowedPluginInfo(url, mime_type, &info, NULL); FilePath plugin_path; - if (NPAPI::PluginList::Singleton()->GetPluginInfo( - url, mime_type, allow_wildcard, &info, NULL) && info.enabled) { - plugin_path = info.path; - } + if (found && info.enabled) + plugin_path = FilePath(info.path); + + // Now we jump back to the IO thread to finish opening the channel. + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableMethod( + this, &PluginService::FinishOpenChannelToPlugin, + renderer_msg_filter, mime_type, plugin_path, reply_msg)); +} + +void PluginService::FinishOpenChannelToPlugin( + ResourceMessageFilter* renderer_msg_filter, + const std::string& mime_type, + const FilePath& plugin_path, + IPC::Message* reply_msg) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); PluginProcessHost* plugin_host = FindOrStartPluginProcess(plugin_path); if (plugin_host) { @@ -264,6 +299,37 @@ void PluginService::OpenChannelToPlugin( } } +bool PluginService::GetFirstAllowedPluginInfo( + const GURL& url, + const std::string& mime_type, + WebPluginInfo* info, + std::string* actual_mime_type) { + // GetPluginInfoArray may need to load the plugins, so we need to be + // on the FILE thread. + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + bool allow_wildcard = true; +#if defined(OS_CHROMEOS) + std::vector<WebPluginInfo> info_array; + std::vector<std::string> actual_mime_types; + NPAPI::PluginList::Singleton()->GetPluginInfoArray( + url, mime_type, allow_wildcard, &info_array, &actual_mime_types); + + // Now we filter by the plugin selection policy. + int allowed_index = plugin_selection_policy_->FindFirstAllowed(url, + info_array); + if (!info_array.empty() && allowed_index >= 0) { + *info = info_array[allowed_index]; + if (actual_mime_type) + *actual_mime_type = actual_mime_types[allowed_index]; + return true; + } + return false; +#else + return NPAPI::PluginList::Singleton()->GetPluginInfo( + url, mime_type, allow_wildcard, info, actual_mime_type); +#endif +} + static void PurgePluginListCache(bool reload_pages) { for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator(); !it.IsAtEnd(); it.Advance()) { diff --git a/chrome/browser/plugin_service.h b/chrome/browser/plugin_service.h index 3f25c25..9ff7988 100644 --- a/chrome/browser/plugin_service.h +++ b/chrome/browser/plugin_service.h @@ -25,6 +25,12 @@ #include "base/scoped_ptr.h" #endif +#if defined(OS_CHROMEOS) +namespace chromeos { +class PluginSelectionPolicy; +} +#endif + namespace IPC { class Message; } @@ -32,9 +38,10 @@ class Message; class MessageLoop; class PluginProcessHost; class Profile; -class URLRequestContext; class ResourceDispatcherHost; class ResourceMessageFilter; +class URLRequestContext; +struct WebPluginInfo; // This must be created on the main thread but it's only called on the IO/file // thread. @@ -78,9 +85,15 @@ class PluginService void OpenChannelToPlugin(ResourceMessageFilter* renderer_msg_filter, const GURL& url, const std::string& mime_type, - const std::string& locale, IPC::Message* reply_msg); + // Gets the first allowed plugin in the list of plugins that matches + // the given url and mime type. Must be called on the FILE thread. + bool GetFirstAllowedPluginInfo(const GURL& url, + const std::string& mime_type, + WebPluginInfo* info, + std::string* actual_mime_type); + // Returns true if the given plugin is allowed to be used by a page with // the given URL. bool PrivatePluginAllowedForURL(const FilePath& plugin_path, const GURL& url); @@ -111,6 +124,21 @@ class PluginService void RegisterPepperPlugins(); + // Helper so we can do the plugin lookup on the FILE thread. + void GetAllowedPluginForOpenChannelToPlugin( + ResourceMessageFilter* renderer_msg_filter, + const GURL& url, + const std::string& mime_type, + IPC::Message* reply_msg); + + // Helper so we can finish opening the channel after looking up the + // plugin. + void FinishOpenChannelToPlugin( + ResourceMessageFilter* renderer_msg_filter, + const std::string& mime_type, + const FilePath& plugin_path, + IPC::Message* reply_msg); + // mapping between plugin path and PluginProcessHost typedef base::hash_map<FilePath, PluginProcessHost*> PluginMap; PluginMap plugin_hosts_; @@ -134,6 +162,10 @@ class PluginService NotificationRegistrar registrar_; +#if defined(OS_CHROMEOS) + scoped_refptr<chromeos::PluginSelectionPolicy> plugin_selection_policy_; +#endif + #if defined(OS_WIN) // Registry keys for getting notifications when new plugins are installed. RegKey hkcu_key_; @@ -150,4 +182,6 @@ class PluginService DISALLOW_COPY_AND_ASSIGN(PluginService); }; +DISABLE_RUNNABLE_METHOD_REFCOUNT(PluginService); + #endif // CHROME_BROWSER_PLUGIN_SERVICE_H_ diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index d62f6d1..cc4e662 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -10,13 +10,13 @@ #if defined(OS_POSIX) #include "base/file_descriptor_posix.h" #endif -#include "base/file_util.h" #include "base/file_path.h" +#include "base/file_util.h" #include "base/metrics/histogram.h" #include "base/process_util.h" #include "base/shared_memory.h" -#include "base/thread.h" #include "base/sys_string_conversions.h" +#include "base/thread.h" #include "base/utf_string_conversions.h" #include "base/worker_pool.h" #include "chrome/browser/appcache/appcache_dispatcher_host.h" @@ -32,8 +32,8 @@ #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/file_system/file_system_dispatcher_host.h" #include "chrome/browser/file_system/file_system_host_context.h" -#include "chrome/browser/geolocation/geolocation_permission_context.h" #include "chrome/browser/geolocation/geolocation_dispatcher_host.h" +#include "chrome/browser/geolocation/geolocation_permission_context.h" #include "chrome/browser/gpu_process_host.h" #include "chrome/browser/host_zoom_map.h" #include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h" @@ -44,8 +44,11 @@ #include "chrome/browser/net/predictor_api.h" #include "chrome/browser/notifications/desktop_notification_service.h" #include "chrome/browser/notifications/notifications_prefs_cache.h" -#include "chrome/browser/plugin_updater.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/plugin_selection_policy.h" +#endif #include "chrome/browser/plugin_service.h" +#include "chrome/browser/plugin_updater.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/printing/printer_query.h" @@ -406,8 +409,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_PreCacheFont, OnPreCacheFont) #endif IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPlugins, OnGetPlugins) - IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPluginInfoArray, - OnGetPluginInfoArray) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPluginInfo, + OnGetPluginInfo) IPC_MESSAGE_HANDLER(ViewHostMsg_DownloadUrl, OnDownloadUrl) IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_ContextMenu, OnReceiveContextMenuMsg(msg)) @@ -759,12 +762,12 @@ void ResourceMessageFilter::OnGetPluginsOnFileThread( NewRunnableMethod(this, &ResourceMessageFilter::Send, reply_msg)); } -void ResourceMessageFilter::OnGetPluginInfoArray(const GURL& url, - const GURL& policy_url, - const std::string& mime_type, - IPC::Message* reply_msg) { - // The PluginList::GetPluginInfo may need to load the plugins. Don't do it - // on the IO thread. +void ResourceMessageFilter::OnGetPluginInfo(const GURL& url, + const GURL& policy_url, + const std::string& mime_type, + IPC::Message* reply_msg) { + // The PluginService::GetFirstAllowedPluginInfo may need to load the + // plugins. Don't do it on the IO thread. BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableMethod( @@ -777,50 +780,45 @@ void ResourceMessageFilter::OnGetPluginInfoOnFileThread( const GURL& policy_url, const std::string& mime_type, IPC::Message* reply_msg) { - std::vector<WebPluginInfo> info; - std::vector<std::string> actual_mime_types; - bool allow_wildcard = true; - NPAPI::PluginList::Singleton()->GetPluginInfoArray( - url, mime_type, allow_wildcard, &info, &actual_mime_types); + std::string actual_mime_type; + WebPluginInfo info; + bool found = plugin_service_->GetFirstAllowedPluginInfo(url, + mime_type, + &info, + &actual_mime_type); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod( this, &ResourceMessageFilter::OnGotPluginInfo, - info, actual_mime_types, policy_url, reply_msg)); -} - -void ResourceMessageFilter::OnGotPluginInfo( - std::vector<WebPluginInfo> info, - const std::vector<std::string>& actual_mime_types, - const GURL& policy_url, - IPC::Message* reply_msg) { - std::vector<ContentSetting> settings; - for (std::vector<WebPluginInfo>::iterator iter = info.begin(); - iter != info.end(); ++iter) { - ContentSetting setting = CONTENT_SETTING_DEFAULT; - WebPluginInfo& item(*iter); - item.enabled = item.enabled && - plugin_service_->PrivatePluginAllowedForURL(item.path, policy_url); + found, info, actual_mime_type, policy_url, reply_msg)); +} + +void ResourceMessageFilter::OnGotPluginInfo(bool found, + WebPluginInfo info, + const std::string& actual_mime_type, + const GURL& policy_url, + IPC::Message* reply_msg) { + ContentSetting setting = CONTENT_SETTING_DEFAULT; + if (found) { + info.enabled = info.enabled && + plugin_service_->PrivatePluginAllowedForURL(info.path, policy_url); HostContentSettingsMap* map = profile_->GetHostContentSettingsMap(); - scoped_ptr<PluginGroup> group(PluginGroup::CopyOrCreatePluginGroup(item)); + scoped_ptr<PluginGroup> group(PluginGroup::CopyOrCreatePluginGroup(info)); std::string resource = group->identifier(); setting = map->GetContentSetting(policy_url, CONTENT_SETTINGS_TYPE_PLUGINS, resource); - settings.push_back(setting); } - ViewHostMsg_GetPluginInfoArray::WriteReplyParams( - reply_msg, info, settings, actual_mime_types); + ViewHostMsg_GetPluginInfo::WriteReplyParams( + reply_msg, found, info, setting, actual_mime_type); Send(reply_msg); } void ResourceMessageFilter::OnOpenChannelToPlugin(const GURL& url, const std::string& mime_type, - const std::string& locale, IPC::Message* reply_msg) { - plugin_service_->OpenChannelToPlugin( - this, url, mime_type, locale, reply_msg); + plugin_service_->OpenChannelToPlugin(this, url, mime_type, reply_msg); } void ResourceMessageFilter::OnLaunchNaCl( diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 52db66c..ca4b920 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -180,22 +180,21 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, #endif void OnGetPlugins(bool refresh, IPC::Message* reply_msg); void OnGetPluginsOnFileThread(bool refresh, IPC::Message* reply_msg); - void OnGetPluginInfoArray(const GURL& url, - const GURL& policy_url, - const std::string& mime_type, - IPC::Message* reply_msg); + void OnGetPluginInfo(const GURL& url, + const GURL& policy_url, + const std::string& mime_type, + IPC::Message* reply_msg); void OnGetPluginInfoOnFileThread(const GURL& url, const GURL& policy_url, const std::string& mime_type, IPC::Message* reply_msg); - void OnGotPluginInfo( - std::vector<WebPluginInfo> info, - const std::vector<std::string>& actual_mime_types, - const GURL& policy_url, - IPC::Message* reply_msg); + void OnGotPluginInfo(bool found, + WebPluginInfo info, + const std::string& actual_mime_type, + const GURL& policy_url, + IPC::Message* reply_msg); void OnOpenChannelToPlugin(const GURL& url, const std::string& mime_type, - const std::string& locale, IPC::Message* reply_msg); void OnLaunchNaCl(const std::wstring& url, int channel_descriptor, |