543 lines
19 KiB
C++
543 lines
19 KiB
C++
// Copyright 2015 The Chromium Embedded Framework Authors.
|
|
// Portions copyright 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 "libcef/browser/plugins/plugin_info_message_filter.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "libcef/browser/browser_context.h"
|
|
#include "libcef/browser/plugins/plugin_service_filter.h"
|
|
#include "libcef/browser/web_plugin_impl.h"
|
|
#include "libcef/common/cef_messages.h"
|
|
#include "libcef/common/extensions/extensions_util.h"
|
|
|
|
#include "base/bind.h"
|
|
#include "base/metrics/histogram_macros.h"
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "base/threading/thread_task_runner_handle.h"
|
|
#include "build/build_config.h"
|
|
#include "chrome/browser/plugins/plugin_finder.h"
|
|
#include "chrome/browser/plugins/plugins_field_trial.h"
|
|
#include "chrome/common/features.h"
|
|
#include "chrome/common/pref_names.h"
|
|
#include "components/content_settings/core/browser/content_settings_utils.h"
|
|
#include "components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h"
|
|
#include "content/public/browser/browser_context.h"
|
|
#include "content/public/browser/browser_thread.h"
|
|
#include "content/public/browser/plugin_service.h"
|
|
#include "content/public/browser/plugin_service_filter.h"
|
|
#include "content/public/common/content_constants.h"
|
|
#include "content/public/common/webplugininfo.h"
|
|
#include "extensions/browser/extension_registry.h"
|
|
#include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
|
|
#include "extensions/common/constants.h"
|
|
#include "extensions/common/extension.h"
|
|
#include "extensions/common/manifest_handlers/webview_info.h"
|
|
#include "url/gurl.h"
|
|
#include "url/origin.h"
|
|
|
|
#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
|
|
|
|
#if !defined(DISABLE_NACL)
|
|
#include "components/nacl/common/nacl_constants.h"
|
|
#endif
|
|
|
|
using content::PluginService;
|
|
using content::WebPluginInfo;
|
|
|
|
namespace {
|
|
|
|
// There's a race condition between deletion of the CefPluginInfoMessageFilter
|
|
// object on the UI thread and deletion of the PrefService (owned by Profile)
|
|
// on the UI thread. If the PrefService will be deleted first then
|
|
// PrefMember::Destroy() must be called from ShutdownOnUIThread() to avoid
|
|
// heap-use-after-free on CefPluginInfoMessageFilter destruction (due to
|
|
// ~PrefMember trying to access the already-deleted PrefService).
|
|
// ShutdownNotifierFactory makes sure that ShutdownOnUIThread() is called in
|
|
// this case.
|
|
class ShutdownNotifierFactory
|
|
: public BrowserContextKeyedServiceShutdownNotifierFactory {
|
|
public:
|
|
static ShutdownNotifierFactory* GetInstance();
|
|
|
|
private:
|
|
friend struct base::LazyInstanceTraitsBase<ShutdownNotifierFactory>;
|
|
|
|
ShutdownNotifierFactory()
|
|
: BrowserContextKeyedServiceShutdownNotifierFactory(
|
|
"CefPluginInfoMessageFilter") {
|
|
}
|
|
~ShutdownNotifierFactory() override {}
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(ShutdownNotifierFactory);
|
|
};
|
|
|
|
base::LazyInstance<ShutdownNotifierFactory>::Leaky
|
|
g_shutdown_notifier_factory = LAZY_INSTANCE_INITIALIZER;
|
|
|
|
// static
|
|
ShutdownNotifierFactory* ShutdownNotifierFactory::GetInstance() {
|
|
return g_shutdown_notifier_factory.Pointer();
|
|
}
|
|
|
|
// For certain sandboxed Pepper plugins, use the JavaScript Content Settings.
|
|
bool ShouldUseJavaScriptSettingForPlugin(const WebPluginInfo& plugin) {
|
|
if (plugin.type != WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS &&
|
|
plugin.type != WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS) {
|
|
return false;
|
|
}
|
|
|
|
#if !defined(DISABLE_NACL)
|
|
// Treat Native Client invocations like JavaScript.
|
|
if (plugin.name == base::ASCIIToUTF16(nacl::kNaClPluginName))
|
|
return true;
|
|
#endif
|
|
|
|
#if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_PEPPER_CDMS)
|
|
// Treat CDM invocations like JavaScript.
|
|
if (plugin.name == base::ASCIIToUTF16(kWidevineCdmDisplayName)) {
|
|
DCHECK(plugin.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS);
|
|
return true;
|
|
}
|
|
#endif // defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_PEPPER_CDMS)
|
|
|
|
return false;
|
|
}
|
|
|
|
#if BUILDFLAG(ENABLE_PEPPER_CDMS)
|
|
|
|
enum PluginAvailabilityStatusForUMA {
|
|
PLUGIN_NOT_REGISTERED,
|
|
PLUGIN_AVAILABLE,
|
|
PLUGIN_DISABLED,
|
|
PLUGIN_AVAILABILITY_STATUS_MAX
|
|
};
|
|
|
|
static void SendPluginAvailabilityUMA(const std::string& mime_type,
|
|
PluginAvailabilityStatusForUMA status) {
|
|
#if defined(WIDEVINE_CDM_AVAILABLE)
|
|
// Only report results for Widevine CDM.
|
|
if (mime_type != kWidevineCdmPluginMimeType)
|
|
return;
|
|
|
|
UMA_HISTOGRAM_ENUMERATION("Plugin.AvailabilityStatus.WidevineCdm",
|
|
status, PLUGIN_AVAILABILITY_STATUS_MAX);
|
|
#endif // defined(WIDEVINE_CDM_AVAILABLE)
|
|
}
|
|
|
|
#endif // BUILDFLAG(ENABLE_PEPPER_CDMS)
|
|
|
|
void ReportMetrics(const std::string& mime_type,
|
|
const GURL& url,
|
|
const url::Origin& main_frame_origin) {
|
|
}
|
|
|
|
#if BUILDFLAG(ENABLE_EXTENSIONS)
|
|
// Returns whether a request from a plugin to load |resource| from a renderer
|
|
// with process id |process_id| is a request for an internal resource by an app
|
|
// listed in |accessible_resources| in its manifest.
|
|
bool IsPluginLoadingAccessibleResourceInWebView(
|
|
extensions::ExtensionRegistry* extension_registry,
|
|
int process_id,
|
|
const GURL& resource) {
|
|
extensions::WebViewRendererState* renderer_state =
|
|
extensions::WebViewRendererState::GetInstance();
|
|
std::string partition_id;
|
|
if (!renderer_state->IsGuest(process_id) ||
|
|
!renderer_state->GetPartitionID(process_id, &partition_id)) {
|
|
return false;
|
|
}
|
|
|
|
const std::string extension_id = resource.host();
|
|
const extensions::Extension* extension = extension_registry->GetExtensionById(
|
|
extension_id, extensions::ExtensionRegistry::ENABLED);
|
|
if (!extension || !extensions::WebviewInfo::IsResourceWebviewAccessible(
|
|
extension, partition_id, resource.path())) {
|
|
return false;
|
|
}
|
|
|
|
// Make sure the renderer making the request actually belongs to the
|
|
// same extension.
|
|
std::string owner_extension;
|
|
return renderer_state->GetOwnerInfo(process_id, nullptr, &owner_extension) &&
|
|
owner_extension == extension_id;
|
|
}
|
|
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
|
|
|
|
} // namespace
|
|
|
|
CefPluginInfoMessageFilter::Context::Context(
|
|
int render_process_id,
|
|
CefBrowserContext* profile)
|
|
: render_process_id_(render_process_id),
|
|
resource_context_(
|
|
static_cast<CefResourceContext*>(profile->GetResourceContext())),
|
|
host_content_settings_map_(profile->GetHostContentSettingsMap()) {
|
|
#if BUILDFLAG(ENABLE_EXTENSIONS)
|
|
if (extensions::ExtensionsEnabled())
|
|
extension_registry_ = extensions::ExtensionRegistry::Get(profile);
|
|
#endif
|
|
|
|
allow_outdated_plugins_.Init(prefs::kPluginsAllowOutdated,
|
|
profile->GetPrefs());
|
|
allow_outdated_plugins_.MoveToThread(
|
|
content::BrowserThread::GetTaskRunnerForThread(
|
|
content::BrowserThread::IO));
|
|
always_authorize_plugins_.Init(prefs::kPluginsAlwaysAuthorize,
|
|
profile->GetPrefs());
|
|
always_authorize_plugins_.MoveToThread(
|
|
content::BrowserThread::GetTaskRunnerForThread(
|
|
content::BrowserThread::IO));
|
|
}
|
|
|
|
CefPluginInfoMessageFilter::Context::~Context() {
|
|
}
|
|
|
|
void CefPluginInfoMessageFilter::Context::ShutdownOnUIThread() {
|
|
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
|
always_authorize_plugins_.Destroy();
|
|
allow_outdated_plugins_.Destroy();
|
|
}
|
|
|
|
CefPluginInfoMessageFilter::CefPluginInfoMessageFilter(
|
|
int render_process_id,
|
|
CefBrowserContext* profile)
|
|
: BrowserMessageFilter(ExtensionMsgStart),
|
|
context_(render_process_id, profile),
|
|
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
|
|
weak_ptr_factory_(this) {
|
|
shutdown_notifier_ =
|
|
ShutdownNotifierFactory::GetInstance()->Get(profile)->Subscribe(
|
|
base::Bind(&CefPluginInfoMessageFilter::ShutdownOnUIThread,
|
|
base::Unretained(this)));
|
|
}
|
|
|
|
void CefPluginInfoMessageFilter::ShutdownOnUIThread() {
|
|
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
|
context_.ShutdownOnUIThread();
|
|
shutdown_notifier_.reset();
|
|
}
|
|
|
|
bool CefPluginInfoMessageFilter::OnMessageReceived(
|
|
const IPC::Message& message) {
|
|
IPC_BEGIN_MESSAGE_MAP(CefPluginInfoMessageFilter, message)
|
|
IPC_MESSAGE_HANDLER_DELAY_REPLY(CefViewHostMsg_GetPluginInfo,
|
|
OnGetPluginInfo)
|
|
#if BUILDFLAG(ENABLE_PEPPER_CDMS)
|
|
IPC_MESSAGE_HANDLER(
|
|
CefViewHostMsg_IsInternalPluginAvailableForMimeType,
|
|
OnIsInternalPluginAvailableForMimeType)
|
|
#endif
|
|
IPC_MESSAGE_UNHANDLED(return false)
|
|
IPC_END_MESSAGE_MAP()
|
|
return true;
|
|
}
|
|
|
|
void CefPluginInfoMessageFilter::OnDestruct() const {
|
|
const_cast<CefPluginInfoMessageFilter*>(this)->
|
|
weak_ptr_factory_.InvalidateWeakPtrs();
|
|
|
|
// Destroy on the UI thread because we contain a |PrefMember|.
|
|
content::BrowserThread::DeleteOnUIThread::Destruct(this);
|
|
}
|
|
|
|
CefPluginInfoMessageFilter::~CefPluginInfoMessageFilter() {}
|
|
|
|
struct CefPluginInfoMessageFilter::GetPluginInfo_Params {
|
|
int render_frame_id;
|
|
GURL url;
|
|
bool is_main_frame;
|
|
url::Origin main_frame_origin;
|
|
std::string mime_type;
|
|
};
|
|
|
|
void CefPluginInfoMessageFilter::OnGetPluginInfo(
|
|
int render_frame_id,
|
|
const GURL& url,
|
|
bool is_main_frame,
|
|
const url::Origin& main_frame_origin,
|
|
const std::string& mime_type,
|
|
IPC::Message* reply_msg) {
|
|
GetPluginInfo_Params params = {
|
|
render_frame_id,
|
|
url,
|
|
is_main_frame,
|
|
main_frame_origin,
|
|
mime_type
|
|
};
|
|
PluginService::GetInstance()->GetPlugins(
|
|
base::Bind(&CefPluginInfoMessageFilter::PluginsLoaded,
|
|
weak_ptr_factory_.GetWeakPtr(),
|
|
params, reply_msg));
|
|
}
|
|
|
|
void CefPluginInfoMessageFilter::PluginsLoaded(
|
|
const GetPluginInfo_Params& params,
|
|
IPC::Message* reply_msg,
|
|
const std::vector<WebPluginInfo>& plugins) {
|
|
CefViewHostMsg_GetPluginInfo_Output output;
|
|
|
|
// This also fills in |actual_mime_type|.
|
|
std::unique_ptr<PluginMetadata> plugin_metadata;
|
|
context_.FindEnabledPlugin(params,
|
|
&output.status, &output.plugin,
|
|
&output.actual_mime_type,
|
|
&plugin_metadata);
|
|
|
|
if (plugin_metadata) {
|
|
output.group_identifier = plugin_metadata->identifier();
|
|
output.group_name = plugin_metadata->name();
|
|
}
|
|
|
|
CefViewHostMsg_GetPluginInfo::WriteReplyParams(reply_msg, output);
|
|
Send(reply_msg);
|
|
if (output.status !=
|
|
CefViewHostMsg_GetPluginInfo_Status::kNotFound) {
|
|
main_thread_task_runner_->PostTask(
|
|
FROM_HERE, base::Bind(&ReportMetrics, output.actual_mime_type,
|
|
params.url, params.main_frame_origin));
|
|
}
|
|
}
|
|
|
|
#if BUILDFLAG(ENABLE_PEPPER_CDMS)
|
|
|
|
void CefPluginInfoMessageFilter::OnIsInternalPluginAvailableForMimeType(
|
|
const std::string& mime_type,
|
|
bool* is_available,
|
|
std::vector<base::string16>* additional_param_names,
|
|
std::vector<base::string16>* additional_param_values) {
|
|
std::vector<WebPluginInfo> plugins;
|
|
PluginService::GetInstance()->GetInternalPlugins(&plugins);
|
|
|
|
bool is_plugin_disabled = false;
|
|
for (size_t i = 0; i < plugins.size(); ++i) {
|
|
const WebPluginInfo& plugin = plugins[i];
|
|
const std::vector<content::WebPluginMimeType>& mime_types =
|
|
plugin.mime_types;
|
|
for (size_t j = 0; j < mime_types.size(); ++j) {
|
|
if (mime_types[j].mime_type == mime_type) {
|
|
if (!context_.IsPluginEnabled(plugin)) {
|
|
is_plugin_disabled = true;
|
|
break;
|
|
}
|
|
|
|
*is_available = true;
|
|
*additional_param_names = mime_types[j].additional_param_names;
|
|
*additional_param_values = mime_types[j].additional_param_values;
|
|
SendPluginAvailabilityUMA(mime_type, PLUGIN_AVAILABLE);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
*is_available = false;
|
|
SendPluginAvailabilityUMA(
|
|
mime_type, is_plugin_disabled ? PLUGIN_DISABLED : PLUGIN_NOT_REGISTERED);
|
|
}
|
|
|
|
#endif // BUILDFLAG(ENABLE_PEPPER_CDMS)
|
|
|
|
void CefPluginInfoMessageFilter::Context::DecidePluginStatus(
|
|
const GetPluginInfo_Params& params,
|
|
const WebPluginInfo& plugin,
|
|
const PluginMetadata* plugin_metadata,
|
|
CefViewHostMsg_GetPluginInfo_Status* status) const {
|
|
PluginMetadata::SecurityStatus plugin_status =
|
|
plugin_metadata->GetSecurityStatus(plugin);
|
|
|
|
if (plugin_status == PluginMetadata::SECURITY_STATUS_FULLY_TRUSTED) {
|
|
*status = CefViewHostMsg_GetPluginInfo_Status::kAllowed;
|
|
return;
|
|
}
|
|
|
|
ContentSetting plugin_setting = CONTENT_SETTING_DEFAULT;
|
|
bool uses_default_content_setting = true;
|
|
bool is_managed = false;
|
|
// Check plugin content settings. The primary URL is the top origin URL and
|
|
// the secondary URL is the plugin URL.
|
|
GetPluginContentSetting(plugin, params.main_frame_origin.GetURL(), params.url,
|
|
plugin_metadata->identifier(), &plugin_setting,
|
|
&uses_default_content_setting, &is_managed);
|
|
|
|
// TODO(tommycli): Remove once we deprecate the plugin ASK policy.
|
|
bool legacy_ask_user = plugin_setting == CONTENT_SETTING_ASK;
|
|
plugin_setting = PluginsFieldTrial::EffectiveContentSetting(
|
|
host_content_settings_map_, CONTENT_SETTINGS_TYPE_PLUGINS,
|
|
plugin_setting);
|
|
|
|
DCHECK(plugin_setting != CONTENT_SETTING_DEFAULT);
|
|
DCHECK(plugin_setting != CONTENT_SETTING_ASK);
|
|
|
|
// Check if the plugin is crashing too much.
|
|
if (PluginService::GetInstance()->IsPluginUnstable(plugin.path) &&
|
|
!always_authorize_plugins_.GetValue() &&
|
|
plugin_setting != CONTENT_SETTING_BLOCK &&
|
|
uses_default_content_setting) {
|
|
*status = CefViewHostMsg_GetPluginInfo_Status::kUnauthorized;
|
|
return;
|
|
}
|
|
|
|
#if BUILDFLAG(ENABLE_EXTENSIONS)
|
|
// If an app has explicitly made internal resources available by listing them
|
|
// in |accessible_resources| in the manifest, then allow them to be loaded by
|
|
// plugins inside a guest-view.
|
|
if (extensions::ExtensionsEnabled() &&
|
|
params.url.SchemeIs(extensions::kExtensionScheme) && !is_managed &&
|
|
plugin_setting == CONTENT_SETTING_BLOCK &&
|
|
IsPluginLoadingAccessibleResourceInWebView(
|
|
extension_registry_, render_process_id_, params.url)) {
|
|
plugin_setting = CONTENT_SETTING_ALLOW;
|
|
}
|
|
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
|
|
|
|
if (plugin_setting == CONTENT_SETTING_DETECT_IMPORTANT_CONTENT) {
|
|
*status = CefViewHostMsg_GetPluginInfo_Status::kPlayImportantContent;
|
|
} else if (plugin_setting == CONTENT_SETTING_BLOCK) {
|
|
// For managed users with the ASK policy, we allow manually running plugins
|
|
// via context menu. This is the closest to admin intent.
|
|
*status = is_managed && !legacy_ask_user
|
|
? CefViewHostMsg_GetPluginInfo_Status::kBlockedByPolicy
|
|
: CefViewHostMsg_GetPluginInfo_Status::kBlocked;
|
|
}
|
|
|
|
#if BUILDFLAG(ENABLE_EXTENSIONS)
|
|
// Allow an embedder of <webview> to block a plugin from being loaded inside
|
|
// the guest. In order to do this, set the status to 'Unauthorized' here,
|
|
// and update the status as appropriate depending on the response from the
|
|
// embedder.
|
|
if (*status == CefViewHostMsg_GetPluginInfo_Status::kAllowed ||
|
|
*status == CefViewHostMsg_GetPluginInfo_Status::kBlocked ||
|
|
*status ==
|
|
CefViewHostMsg_GetPluginInfo_Status::kPlayImportantContent) {
|
|
if (extensions::WebViewRendererState::GetInstance()->IsGuest(
|
|
render_process_id_)) {
|
|
*status = CefViewHostMsg_GetPluginInfo_Status::kUnauthorized;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool CefPluginInfoMessageFilter::Context::FindEnabledPlugin(
|
|
const GetPluginInfo_Params& params,
|
|
CefViewHostMsg_GetPluginInfo_Status* status,
|
|
WebPluginInfo* plugin,
|
|
std::string* actual_mime_type,
|
|
std::unique_ptr<PluginMetadata>* plugin_metadata) const {
|
|
*status = CefViewHostMsg_GetPluginInfo_Status::kAllowed;
|
|
|
|
bool allow_wildcard = true;
|
|
std::vector<WebPluginInfo> matching_plugins;
|
|
std::vector<std::string> mime_types;
|
|
PluginService::GetInstance()->GetPluginInfoArray(
|
|
params.url, params.mime_type, allow_wildcard, &matching_plugins,
|
|
&mime_types);
|
|
if (matching_plugins.empty()) {
|
|
*status = CefViewHostMsg_GetPluginInfo_Status::kNotFound;
|
|
return false;
|
|
}
|
|
|
|
CefPluginServiceFilter* filter = static_cast<CefPluginServiceFilter*>(
|
|
PluginService::GetInstance()->GetFilter());
|
|
DCHECK(filter);
|
|
|
|
CefViewHostMsg_GetPluginInfo_Status first_status = *status;
|
|
|
|
size_t i = 0;
|
|
for (; i < matching_plugins.size(); ++i) {
|
|
*plugin = matching_plugins[i];
|
|
*actual_mime_type = mime_types[i];
|
|
*plugin_metadata = PluginFinder::GetInstance()->GetPluginMetadata(*plugin);
|
|
|
|
DecidePluginStatus(params, *plugin, (*plugin_metadata).get(), status);
|
|
if (filter->IsPluginAvailable(render_process_id_,
|
|
resource_context_,
|
|
params.url,
|
|
params.is_main_frame,
|
|
params.main_frame_origin,
|
|
plugin,
|
|
status)) {
|
|
break;
|
|
}
|
|
|
|
if (i == 0)
|
|
first_status = *status;
|
|
}
|
|
|
|
// If we broke out of the loop, we have found an enabled plugin.
|
|
bool enabled = i < matching_plugins.size();
|
|
if (!enabled) {
|
|
// Otherwise, we only found disabled/not-found plugins, so we take the first
|
|
// one.
|
|
*plugin = matching_plugins[0];
|
|
*actual_mime_type = mime_types[0];
|
|
*plugin_metadata = PluginFinder::GetInstance()->GetPluginMetadata(*plugin);
|
|
*status = first_status;
|
|
}
|
|
|
|
return enabled;
|
|
}
|
|
|
|
void CefPluginInfoMessageFilter::Context::GetPluginContentSetting(
|
|
const WebPluginInfo& plugin,
|
|
const GURL& policy_url,
|
|
const GURL& plugin_url,
|
|
const std::string& resource,
|
|
ContentSetting* setting,
|
|
bool* uses_default_content_setting,
|
|
bool* is_managed) const {
|
|
std::unique_ptr<base::Value> value;
|
|
content_settings::SettingInfo info;
|
|
bool uses_plugin_specific_setting = false;
|
|
if (ShouldUseJavaScriptSettingForPlugin(plugin)) {
|
|
value = host_content_settings_map_->GetWebsiteSetting(
|
|
policy_url,
|
|
policy_url,
|
|
CONTENT_SETTINGS_TYPE_JAVASCRIPT,
|
|
std::string(),
|
|
&info);
|
|
} else {
|
|
content_settings::SettingInfo specific_info;
|
|
std::unique_ptr<base::Value> specific_setting =
|
|
host_content_settings_map_->GetWebsiteSetting(
|
|
policy_url,
|
|
plugin_url,
|
|
CONTENT_SETTINGS_TYPE_PLUGINS,
|
|
resource,
|
|
&specific_info);
|
|
content_settings::SettingInfo general_info;
|
|
std::unique_ptr<base::Value> general_setting =
|
|
host_content_settings_map_->GetWebsiteSetting(
|
|
policy_url,
|
|
plugin_url,
|
|
CONTENT_SETTINGS_TYPE_PLUGINS,
|
|
std::string(),
|
|
&general_info);
|
|
|
|
// If there is a plugin-specific setting, we use it, unless the general
|
|
// setting was set by policy, in which case it takes precedence.
|
|
uses_plugin_specific_setting =
|
|
specific_setting &&
|
|
general_info.source != content_settings::SETTING_SOURCE_POLICY;
|
|
if (uses_plugin_specific_setting) {
|
|
value = std::move(specific_setting);
|
|
info = specific_info;
|
|
} else {
|
|
value = std::move(general_setting);
|
|
info = general_info;
|
|
}
|
|
}
|
|
*setting = content_settings::ValueToContentSetting(value.get());
|
|
*uses_default_content_setting =
|
|
!uses_plugin_specific_setting &&
|
|
info.primary_pattern == ContentSettingsPattern::Wildcard() &&
|
|
info.secondary_pattern == ContentSettingsPattern::Wildcard();
|
|
*is_managed = info.source == content_settings::SETTING_SOURCE_POLICY;
|
|
}
|
|
|
|
bool CefPluginInfoMessageFilter::Context::IsPluginEnabled(
|
|
const content::WebPluginInfo& plugin) const {
|
|
return true;
|
|
}
|