diff options
author | gspencer@chromium.org <gspencer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-15 21:50:28 +0000 |
---|---|---|
committer | gspencer@chromium.org <gspencer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-15 21:50:28 +0000 |
commit | d4a7cc0322939beab17c17f7b6d5155115047a42 (patch) | |
tree | f5f2d9a17c9d5b805d3de7bf746906e708ccca3f | |
parent | d3055ce66417c6117c31e81d8d841c4fe4ba1fa9 (diff) | |
download | chromium_src-d4a7cc0322939beab17c17f7b6d5155115047a42.zip chromium_src-d4a7cc0322939beab17c17f7b6d5155115047a42.tar.gz chromium_src-d4a7cc0322939beab17c17f7b6d5155115047a42.tar.bz2 |
Merge 62679 [2nd try] - 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
TBR=gspencer@chromium.org
Review URL: http://codereview.chromium.org/3814008
git-svn-id: svn://svn.chromium.org/chrome/branches/552/src@62800 0039d316-1c4b-4281-b951-d872f2087c98
-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 | 28 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 1 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 3 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 35 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 46 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_proxy.cc | 3 |
12 files changed, 687 insertions, 64 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 e42c2ae..7b0dd47 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,16 +253,41 @@ 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)); - bool allow_wildcard = true; + // 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)); +} +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) { plugin_host->OpenChannelToPlugin(renderer_msg_filter, mime_type, reply_msg); @@ -262,6 +297,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 1c5e569..d1398d6 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/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" @@ -763,8 +766,8 @@ void ResourceMessageFilter::OnGetPluginInfo(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. + // 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,11 +780,12 @@ void ResourceMessageFilter::OnGetPluginInfoOnFileThread( const GURL& policy_url, const std::string& mime_type, IPC::Message* reply_msg) { - WebPluginInfo info; std::string actual_mime_type; - bool allow_wildcard = true; - bool found = NPAPI::PluginList::Singleton()->GetPluginInfo( - url, mime_type, allow_wildcard, &info, &actual_mime_type); + WebPluginInfo info; + bool found = plugin_service_->GetFirstAllowedPluginInfo(url, + mime_type, + &info, + &actual_mime_type); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod( @@ -813,10 +817,8 @@ void ResourceMessageFilter::OnGotPluginInfo(bool found, 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 0123ce6..6a8bdd7 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -195,7 +195,6 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, 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, diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 3b19fd4..434b08c 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -691,6 +691,8 @@ 'browser/chromeos/panels/panel_scroller_header.h', 'browser/chromeos/pipe_reader.cc', 'browser/chromeos/pipe_reader.h', + 'browser/chromeos/plugin_selection_policy.cc', + 'browser/chromeos/plugin_selection_policy.h', 'browser/chromeos/preferences.cc', 'browser/chromeos/preferences.h', 'browser/chromeos/proxy_config_service.h', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 326655a..2b8ffab 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -672,7 +672,7 @@ 'test/webdriver/commands/session_with_id.h', 'test/webdriver/commands/session_with_id.cc', 'test/webdriver/commands/source_command.h', - 'test/webdriver/commands/source_command.cc', + 'test/webdriver/commands/source_command.cc', 'test/webdriver/commands/title_command.h', 'test/webdriver/commands/title_command.cc', 'test/webdriver/commands/url_command.h', @@ -1065,6 +1065,7 @@ 'browser/chromeos/offline/offline_load_page_unittest.cc', 'browser/chromeos/options/language_config_model_unittest.cc', 'browser/chromeos/pipe_reader_unittest.cc', + 'browser/chromeos/plugin_selection_policy_unittest.cc', 'browser/chromeos/proxy_config_service_impl_unittest.cc', 'browser/chromeos/status/input_method_menu_unittest.cc', 'browser/chromeos/version_loader_unittest.cc', diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 2aa3e73..1307799 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1366,19 +1366,27 @@ IPC_BEGIN_MESSAGES(ViewHost) bool /* refresh*/, std::vector<WebPluginInfo> /* plugins */) - // Return information about a plugin for the given URL and MIME type. If there - // is no matching plugin, |found| is set to false. - // If |enabled| in the WebPluginInfo struct is false, the plug-in is basically + // Return information about a plugin for the given URL and MIME + // type. If there is no matching plugin, |found| is false. If + // |enabled| in the WebPluginInfo struct is false, the plug-in is // treated as if it was not installed at all. - // If |setting| is set to CONTENT_SETTING_BLOCK, the plug-in is blocked by the - // content settings for |policy_url|. It still appears in navigator.plugins in - // Javascript though, and can be loaded via click-to-play. - // If |setting| is set to CONTENT_SETTING_ALLOW, the domain is explicitly - // white-listed for the plug-in, or the user has chosen not to block - // nonsandboxed plugins. - // If |setting| is set to CONTENT_SETTING_DEFAULT, the plug-in is neither - // blocked nor white-listed, which means that it's allowed by default and - // can still be blocked if it's non-sandboxed. + // + // If |setting| is set to CONTENT_SETTING_BLOCK, the plug-in is + // blocked by the content settings for |policy_url|. It still + // appears in navigator.plugins in Javascript though, and can be + // loaded via click-to-play. + // + // If |setting| is set to CONTENT_SETTING_ALLOW, the domain is + // explicitly white-listed for the plug-in, or the user has chosen + // not to block nonsandboxed plugins. + // + // If |setting| is set to CONTENT_SETTING_DEFAULT, the plug-in is + // neither blocked nor white-listed, which means that it's allowed + // by default and can still be blocked if it's non-sandboxed. + // + // |actual_mime_type| is the actual mime type supported by the + // plugin found that match the URL given (one for each item in + // |info|). IPC_SYNC_MESSAGE_CONTROL3_4(ViewHostMsg_GetPluginInfo, GURL /* url */, GURL /* policy_url */, @@ -1524,10 +1532,9 @@ IPC_BEGIN_MESSAGES(ViewHost) // create a plugin. The browser will create the plugin process if // necessary, and will return a handle to the channel on success. // On error an empty string is returned. - IPC_SYNC_MESSAGE_CONTROL3_2(ViewHostMsg_OpenChannelToPlugin, + IPC_SYNC_MESSAGE_CONTROL2_2(ViewHostMsg_OpenChannelToPlugin, GURL /* url */, std::string /* mime_type */, - std::string /* locale */, IPC::ChannelHandle /* handle to channel */, WebPluginInfo /* info */) diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index d1c19252..9118de4 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -9,8 +9,8 @@ #include <string> #include <vector> -#include "app/message_box_flags.h" #include "app/l10n_util.h" +#include "app/message_box_flags.h" #include "app/resource_bundle.h" #include "base/callback.h" #include "base/command_line.h" @@ -22,8 +22,8 @@ #include "base/singleton.h" #include "base/string_piece.h" #include "base/string_util.h" -#include "base/time.h" #include "base/sys_string_conversions.h" +#include "base/time.h" #include "base/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/common/appcache/appcache_dispatcher.h" @@ -56,9 +56,9 @@ #include "chrome/renderer/dom_ui_bindings.h" #include "chrome/renderer/extension_groups.h" #include "chrome/renderer/extensions/bindings_utils.h" -#include "chrome/renderer/extensions/extension_renderer_info.h" #include "chrome/renderer/extensions/event_bindings.h" #include "chrome/renderer/extensions/extension_process_bindings.h" +#include "chrome/renderer/extensions/extension_renderer_info.h" #include "chrome/renderer/extensions/renderer_extension_bindings.h" #include "chrome/renderer/external_host_bindings.h" #include "chrome/renderer/geolocation_dispatcher.h" @@ -101,8 +101,6 @@ #include "net/base/net_errors.h" #include "skia/ext/bitmap_platform_device.h" #include "skia/ext/image_operations.h" -#include "third_party/cld/encodings/compact_lang_det/win/cld_unicodetext.h" -#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityCache.h" #include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityObject.h" #include "third_party/WebKit/WebKit/chromium/public/WebCString.h" @@ -111,9 +109,9 @@ #include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/WebKit/chromium/public/WebDragData.h" #include "third_party/WebKit/WebKit/chromium/public/WebFileChooserParams.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFindOptions.h" #include "third_party/WebKit/WebKit/chromium/public/WebFileSystem.h" #include "third_party/WebKit/WebKit/chromium/public/WebFileSystemCallbacks.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFindOptions.h" #include "third_party/WebKit/WebKit/chromium/public/WebFormControlElement.h" #include "third_party/WebKit/WebKit/chromium/public/WebFormElement.h" #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" @@ -126,8 +124,8 @@ #include "third_party/WebKit/WebKit/chromium/public/WebPageSerializer.h" #include "third_party/WebKit/WebKit/chromium/public/WebPlugin.h" #include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h" -#include "third_party/WebKit/WebKit/chromium/public/WebPluginParams.h" #include "third_party/WebKit/WebKit/chromium/public/WebPluginDocument.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPluginParams.h" #include "third_party/WebKit/WebKit/chromium/public/WebPoint.h" #include "third_party/WebKit/WebKit/chromium/public/WebRange.h" #include "third_party/WebKit/WebKit/chromium/public/WebRect.h" @@ -145,6 +143,8 @@ #include "third_party/WebKit/WebKit/chromium/public/WebVector.h" #include "third_party/WebKit/WebKit/chromium/public/WebView.h" #include "third_party/WebKit/WebKit/chromium/public/WebWindowFeatures.h" +#include "third_party/cld/encodings/compact_lang_det/win/cld_unicodetext.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "v8/include/v8.h" #include "webkit/appcache/web_application_cache_host_impl.h" #include "webkit/glue/context_menu.h" @@ -182,28 +182,17 @@ #include "skia/ext/skia_utils_mac.h" #endif -using appcache::WebApplicationCacheHostImpl; -using base::Time; -using base::TimeDelta; -using webkit_glue::AltErrorPageResourceFetcher; -using webkit_glue::FormData; -using webkit_glue::FormField; -using webkit_glue::ImageResourceFetcher; -using webkit_glue::PasswordForm; -using webkit_glue::PasswordFormDomManager; -using webkit_glue::SiteIsolationMetrics; -using webkit_glue::WebAccessibility; using WebKit::WebAccessibilityCache; using WebKit::WebAccessibilityNotification; using WebKit::WebAccessibilityObject; using WebKit::WebApplicationCacheHost; using WebKit::WebApplicationCacheHostClient; +using WebKit::WebCString; using WebKit::WebColor; using WebKit::WebColorName; using WebKit::WebConsoleMessage; using WebKit::WebContextMenuData; using WebKit::WebCookieJar; -using WebKit::WebCString; using WebKit::WebData; using WebKit::WebDataSource; using WebKit::WebDevToolsAgent; @@ -255,9 +244,20 @@ using WebKit::WebURLResponse; using WebKit::WebVector; using WebKit::WebView; using WebKit::WebWidget; +using WebKit::WebWindowFeatures; using WebKit::WebWorker; using WebKit::WebWorkerClient; -using WebKit::WebWindowFeatures; +using appcache::WebApplicationCacheHostImpl; +using base::Time; +using base::TimeDelta; +using webkit_glue::AltErrorPageResourceFetcher; +using webkit_glue::FormData; +using webkit_glue::FormField; +using webkit_glue::ImageResourceFetcher; +using webkit_glue::PasswordForm; +using webkit_glue::PasswordFormDomManager; +using webkit_glue::SiteIsolationMetrics; +using webkit_glue::WebAccessibility; //----------------------------------------------------------------------------- @@ -299,10 +299,8 @@ static const int kDelaySecondsForContentStateSync = 1; // The maximum number of popups that can be spawned from one page. static const int kMaximumNumberOfUnacknowledgedPopups = 25; -static const char* const kUnreachableWebDataURL = - "chrome://chromewebdata/"; - -static const char* const kBackForwardNavigationScheme = "history"; +static const char kUnreachableWebDataURL[] = "chrome://chromewebdata/"; +static const char kBackForwardNavigationScheme[] = "history"; static void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) { WebVector<WebURL> urls; diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index de4381d..5585eb7 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -274,8 +274,7 @@ bool WebPluginDelegateProxy::Initialize(const GURL& url, bool load_manually) { IPC::ChannelHandle channel_handle; if (!RenderThread::current()->Send(new ViewHostMsg_OpenChannelToPlugin( - url, mime_type_, webkit_glue::GetWebKitLocale(), - &channel_handle, &info_))) { + url, mime_type_, &channel_handle, &info_))) { return false; } |