| // Copyright (c) 2012 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/plugins/chrome_plugin_service_filter.h" |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/plugins/plugin_metadata.h" |
| #include "chrome/browser/plugins/plugin_prefs.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/render_messages.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/plugin_service.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/resource_context.h" |
| #include "content/public/browser/web_contents.h" |
| |
| using content::BrowserThread; |
| using content::PluginService; |
| |
| namespace { |
| |
| void AuthorizeRenderer(content::RenderFrameHost* render_frame_host) { |
| ChromePluginServiceFilter::GetInstance()->AuthorizePlugin( |
| render_frame_host->GetProcess()->GetID(), base::FilePath()); |
| } |
| |
| } |
| |
| // static |
| ChromePluginServiceFilter* ChromePluginServiceFilter::GetInstance() { |
| return Singleton<ChromePluginServiceFilter>::get(); |
| } |
| |
| void ChromePluginServiceFilter::RegisterResourceContext( |
| PluginPrefs* plugin_prefs, |
| const void* context) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| base::AutoLock lock(lock_); |
| resource_context_map_[context] = plugin_prefs; |
| } |
| |
| void ChromePluginServiceFilter::UnregisterResourceContext( |
| const void* context) { |
| base::AutoLock lock(lock_); |
| resource_context_map_.erase(context); |
| } |
| |
| void ChromePluginServiceFilter::OverridePluginForFrame( |
| int render_process_id, |
| int render_frame_id, |
| const GURL& url, |
| const content::WebPluginInfo& plugin) { |
| base::AutoLock auto_lock(lock_); |
| ProcessDetails* details = GetOrRegisterProcess(render_process_id); |
| OverriddenPlugin overridden_plugin; |
| overridden_plugin.render_frame_id = render_frame_id; |
| overridden_plugin.url = url; |
| overridden_plugin.plugin = plugin; |
| details->overridden_plugins.push_back(overridden_plugin); |
| } |
| |
| void ChromePluginServiceFilter::RestrictPluginToProfileAndOrigin( |
| const base::FilePath& plugin_path, |
| Profile* profile, |
| const GURL& origin) { |
| base::AutoLock auto_lock(lock_); |
| restricted_plugins_[plugin_path] = |
| std::make_pair(PluginPrefs::GetForProfile(profile).get(), origin); |
| } |
| |
| void ChromePluginServiceFilter::UnrestrictPlugin( |
| const base::FilePath& plugin_path) { |
| base::AutoLock auto_lock(lock_); |
| restricted_plugins_.erase(plugin_path); |
| } |
| |
| bool ChromePluginServiceFilter::IsPluginRestricted( |
| const base::FilePath& plugin_path) { |
| base::AutoLock auto_lock(lock_); |
| return restricted_plugins_.find(plugin_path) != restricted_plugins_.end(); |
| } |
| |
| bool ChromePluginServiceFilter::IsPluginAvailable( |
| int render_process_id, |
| int render_frame_id, |
| const void* context, |
| const GURL& url, |
| const GURL& policy_url, |
| content::WebPluginInfo* plugin) { |
| base::AutoLock auto_lock(lock_); |
| const ProcessDetails* details = GetProcess(render_process_id); |
| |
| // Check whether the plugin is overridden. |
| if (details) { |
| for (size_t i = 0; i < details->overridden_plugins.size(); ++i) { |
| if (details->overridden_plugins[i].render_frame_id == render_frame_id && |
| (details->overridden_plugins[i].url == url || |
| details->overridden_plugins[i].url.is_empty())) { |
| |
| bool use = details->overridden_plugins[i].plugin.path == plugin->path; |
| if (use) |
| *plugin = details->overridden_plugins[i].plugin; |
| return use; |
| } |
| } |
| } |
| |
| // Check whether the plugin is disabled. |
| ResourceContextMap::iterator prefs_it = |
| resource_context_map_.find(context); |
| if (prefs_it == resource_context_map_.end()) |
| return false; |
| |
| PluginPrefs* plugin_prefs = prefs_it->second.get(); |
| if (!plugin_prefs->IsPluginEnabled(*plugin)) |
| return false; |
| |
| // Check whether the plugin is restricted to a URL. |
| RestrictedPluginMap::const_iterator it = |
| restricted_plugins_.find(plugin->path); |
| if (it != restricted_plugins_.end()) { |
| if (it->second.first != plugin_prefs) |
| return false; |
| const GURL& origin = it->second.second; |
| if (!origin.is_empty() && |
| (policy_url.scheme() != origin.scheme() || |
| policy_url.host() != origin.host() || |
| policy_url.port() != origin.port())) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| bool ChromePluginServiceFilter::CanLoadPlugin(int render_process_id, |
| const base::FilePath& path) { |
| // The browser itself sometimes loads plug-ins to e.g. clear plug-in data. |
| // We always grant the browser permission. |
| if (!render_process_id) |
| return true; |
| |
| base::AutoLock auto_lock(lock_); |
| const ProcessDetails* details = GetProcess(render_process_id); |
| if (!details) |
| return false; |
| |
| if (details->authorized_plugins.find(path) == |
| details->authorized_plugins.end() && |
| details->authorized_plugins.find(base::FilePath()) == |
| details->authorized_plugins.end()) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void ChromePluginServiceFilter::AuthorizePlugin( |
| int render_process_id, |
| const base::FilePath& plugin_path) { |
| base::AutoLock auto_lock(lock_); |
| ProcessDetails* details = GetOrRegisterProcess(render_process_id); |
| details->authorized_plugins.insert(plugin_path); |
| } |
| |
| void ChromePluginServiceFilter::AuthorizeAllPlugins( |
| content::WebContents* web_contents, |
| bool load_blocked, |
| const std::string& identifier) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| web_contents->ForEachFrame(base::Bind(&AuthorizeRenderer)); |
| if (load_blocked) { |
| web_contents->SendToAllFrames(new ChromeViewMsg_LoadBlockedPlugins( |
| MSG_ROUTING_NONE, identifier)); |
| } |
| } |
| |
| ChromePluginServiceFilter::ChromePluginServiceFilter() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, |
| content::NotificationService::AllSources()); |
| } |
| |
| ChromePluginServiceFilter::~ChromePluginServiceFilter() { |
| } |
| |
| void ChromePluginServiceFilter::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| switch (type) { |
| case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { |
| int render_process_id = |
| content::Source<content::RenderProcessHost>(source).ptr()->GetID(); |
| |
| base::AutoLock auto_lock(lock_); |
| plugin_details_.erase(render_process_id); |
| break; |
| } |
| case chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED: { |
| Profile* profile = content::Source<Profile>(source).ptr(); |
| PluginService::GetInstance()->PurgePluginListCache(profile, false); |
| if (profile && profile->HasOffTheRecordProfile()) { |
| PluginService::GetInstance()->PurgePluginListCache( |
| profile->GetOffTheRecordProfile(), false); |
| } |
| break; |
| } |
| default: { |
| NOTREACHED(); |
| } |
| } |
| } |
| |
| ChromePluginServiceFilter::ProcessDetails* |
| ChromePluginServiceFilter::GetOrRegisterProcess( |
| int render_process_id) { |
| return &plugin_details_[render_process_id]; |
| } |
| |
| const ChromePluginServiceFilter::ProcessDetails* |
| ChromePluginServiceFilter::GetProcess( |
| int render_process_id) const { |
| std::map<int, ProcessDetails>::const_iterator it = |
| plugin_details_.find(render_process_id); |
| if (it == plugin_details_.end()) |
| return NULL; |
| return &it->second; |
| } |
| |
| ChromePluginServiceFilter::OverriddenPlugin::OverriddenPlugin() |
| : render_frame_id(MSG_ROUTING_NONE) { |
| } |
| |
| ChromePluginServiceFilter::OverriddenPlugin::~OverriddenPlugin() { |
| } |
| |
| ChromePluginServiceFilter::ProcessDetails::ProcessDetails() { |
| } |
| |
| ChromePluginServiceFilter::ProcessDetails::~ProcessDetails() { |
| } |
| |