1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/content_settings/content_settings_api.h"
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/browser/content_settings/cookie_settings_factory.h"
16 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
17 #include "chrome/browser/extensions/api/content_settings/content_settings_api_constants.h"
18 #include "chrome/browser/extensions/api/content_settings/content_settings_helpers.h"
19 #include "chrome/browser/extensions/api/content_settings/content_settings_service.h"
20 #include "chrome/browser/extensions/api/content_settings/content_settings_store.h"
21 #include "chrome/browser/extensions/api/preference/preference_api_constants.h"
22 #include "chrome/browser/extensions/api/preference/preference_helpers.h"
23 #include "chrome/browser/plugins/plugin_finder.h"
24 #include "chrome/browser/plugins/plugin_installer.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/extensions/api/content_settings.h"
28 #include "components/content_settings/core/browser/cookie_settings.h"
29 #include "components/content_settings/core/browser/host_content_settings_map.h"
30 #include "content/public/browser/plugin_service.h"
31 #include "extensions/browser/extension_prefs_scope.h"
32 #include "extensions/common/error_utils.h"
34 using content::BrowserThread
;
35 using content::PluginService
;
37 namespace Clear
= extensions::api::content_settings::ContentSetting::Clear
;
38 namespace Get
= extensions::api::content_settings::ContentSetting::Get
;
39 namespace Set
= extensions::api::content_settings::ContentSetting::Set
;
40 namespace pref_helpers
= extensions::preference_helpers
;
41 namespace pref_keys
= extensions::preference_api_constants
;
45 bool RemoveContentType(base::ListValue
* args
,
46 ContentSettingsType
* content_type
) {
47 std::string content_type_str
;
48 if (!args
->GetString(0, &content_type_str
))
50 // We remove the ContentSettingsType parameter since this is added by the
51 // renderer, and is not part of the JSON schema.
52 args
->Remove(0, NULL
);
54 extensions::content_settings_helpers::StringToContentSettingsType(
56 return *content_type
!= CONTENT_SETTINGS_TYPE_DEFAULT
;
61 namespace extensions
{
63 namespace helpers
= content_settings_helpers
;
64 namespace keys
= content_settings_api_constants
;
66 bool ContentSettingsContentSettingClearFunction::RunSync() {
67 ContentSettingsType content_type
;
68 EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_
.get(), &content_type
));
70 scoped_ptr
<Clear::Params
> params(Clear::Params::Create(*args_
));
71 EXTENSION_FUNCTION_VALIDATE(params
.get());
73 ExtensionPrefsScope scope
= kExtensionPrefsScopeRegular
;
74 bool incognito
= false;
75 if (params
->details
.scope
==
76 api::content_settings::SCOPE_INCOGNITO_SESSION_ONLY
) {
77 scope
= kExtensionPrefsScopeIncognitoSessionOnly
;
82 // We don't check incognito permissions here, as an extension should be
83 // always allowed to clear its own settings.
85 // Incognito profiles can't access regular mode ever, they only exist in
87 if (GetProfile()->IsOffTheRecord()) {
88 error_
= keys::kIncognitoContextError
;
93 scoped_refptr
<ContentSettingsStore
> store
=
94 ContentSettingsService::Get(GetProfile())->content_settings_store();
95 store
->ClearContentSettingsForExtension(extension_id(), scope
);
100 bool ContentSettingsContentSettingGetFunction::RunSync() {
101 ContentSettingsType content_type
;
102 EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_
.get(), &content_type
));
104 scoped_ptr
<Get::Params
> params(Get::Params::Create(*args_
));
105 EXTENSION_FUNCTION_VALIDATE(params
.get());
107 GURL
primary_url(params
->details
.primary_url
);
108 if (!primary_url
.is_valid()) {
109 error_
= ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError
,
110 params
->details
.primary_url
);
114 GURL
secondary_url(primary_url
);
115 if (params
->details
.secondary_url
.get()) {
116 secondary_url
= GURL(*params
->details
.secondary_url
);
117 if (!secondary_url
.is_valid()) {
118 error_
= ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError
,
119 *params
->details
.secondary_url
);
124 std::string resource_identifier
;
125 if (params
->details
.resource_identifier
.get())
126 resource_identifier
= params
->details
.resource_identifier
->id
;
128 bool incognito
= false;
129 if (params
->details
.incognito
.get())
130 incognito
= *params
->details
.incognito
;
131 if (incognito
&& !include_incognito()) {
132 error_
= pref_keys::kIncognitoErrorMessage
;
136 HostContentSettingsMap
* map
;
137 content_settings::CookieSettings
* cookie_settings
;
139 if (!GetProfile()->HasOffTheRecordProfile()) {
140 // TODO(bauerb): Allow reading incognito content settings
141 // outside of an incognito session.
142 error_
= keys::kIncognitoSessionOnlyError
;
145 map
= HostContentSettingsMapFactory::GetForProfile(
146 GetProfile()->GetOffTheRecordProfile());
147 cookie_settings
= CookieSettingsFactory::GetForProfile(
148 GetProfile()->GetOffTheRecordProfile()).get();
150 map
= HostContentSettingsMapFactory::GetForProfile(GetProfile());
151 cookie_settings
= CookieSettingsFactory::GetForProfile(GetProfile()).get();
154 ContentSetting setting
;
155 if (content_type
== CONTENT_SETTINGS_TYPE_COOKIES
) {
156 // TODO(jochen): Do we return the value for setting or for reading cookies?
157 bool setting_cookie
= false;
158 setting
= cookie_settings
->GetCookieSetting(primary_url
, secondary_url
,
159 setting_cookie
, NULL
);
161 setting
= map
->GetContentSetting(primary_url
, secondary_url
, content_type
,
162 resource_identifier
);
165 base::DictionaryValue
* result
= new base::DictionaryValue();
166 result
->SetString(keys::kContentSettingKey
,
167 helpers::ContentSettingToString(setting
));
174 bool ContentSettingsContentSettingSetFunction::RunSync() {
175 ContentSettingsType content_type
;
176 EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_
.get(), &content_type
));
178 scoped_ptr
<Set::Params
> params(Set::Params::Create(*args_
));
179 EXTENSION_FUNCTION_VALIDATE(params
.get());
181 std::string primary_error
;
182 ContentSettingsPattern primary_pattern
=
183 helpers::ParseExtensionPattern(params
->details
.primary_pattern
,
185 if (!primary_pattern
.IsValid()) {
186 error_
= primary_error
;
190 ContentSettingsPattern secondary_pattern
= ContentSettingsPattern::Wildcard();
191 if (params
->details
.secondary_pattern
.get()) {
192 std::string secondary_error
;
194 helpers::ParseExtensionPattern(*params
->details
.secondary_pattern
,
196 if (!secondary_pattern
.IsValid()) {
197 error_
= secondary_error
;
202 std::string resource_identifier
;
203 if (params
->details
.resource_identifier
.get())
204 resource_identifier
= params
->details
.resource_identifier
->id
;
206 std::string setting_str
;
207 EXTENSION_FUNCTION_VALIDATE(
208 params
->details
.setting
->GetAsString(&setting_str
));
209 ContentSetting setting
;
210 EXTENSION_FUNCTION_VALIDATE(
211 helpers::StringToContentSetting(setting_str
, &setting
));
212 EXTENSION_FUNCTION_VALIDATE(HostContentSettingsMap::IsSettingAllowedForType(
213 GetProfile()->GetPrefs(), setting
, content_type
));
215 // Some content setting types support the full set of values listed in
216 // content_settings.json only for exceptions. For the default setting,
217 // some values might not be supported.
218 // For example, camera supports [allow, ask, block] for exceptions, but only
219 // [ask, block] for the default setting.
220 if (primary_pattern
== ContentSettingsPattern::Wildcard() &&
221 secondary_pattern
== ContentSettingsPattern::Wildcard() &&
222 !HostContentSettingsMap::IsDefaultSettingAllowedForType(
223 GetProfile()->GetPrefs(), setting
, content_type
)) {
224 static const char kUnsupportedDefaultSettingError
[] =
225 "'%s' is not supported as the default setting of %s.";
227 // TODO(msramek): Get the same human readable name as is presented
228 // externally in the API, i.e. chrome.contentSettings.<name>.set().
229 std::string readable_type_name
;
230 switch (content_type
) {
231 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
:
232 readable_type_name
= "microphone";
234 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
:
235 readable_type_name
= "camera";
238 DCHECK(false) << "No human-readable type name defined for this type.";
241 error_
= base::StringPrintf(
242 kUnsupportedDefaultSettingError
,
243 content_settings_helpers::ContentSettingToString(setting
),
244 readable_type_name
.c_str());
248 ExtensionPrefsScope scope
= kExtensionPrefsScopeRegular
;
249 bool incognito
= false;
250 if (params
->details
.scope
==
251 api::content_settings::SCOPE_INCOGNITO_SESSION_ONLY
) {
252 scope
= kExtensionPrefsScopeIncognitoSessionOnly
;
257 // Regular profiles can't access incognito unless include_incognito is true.
258 if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
259 error_
= pref_keys::kIncognitoErrorMessage
;
263 // Incognito profiles can't access regular mode ever, they only exist in
265 if (GetProfile()->IsOffTheRecord()) {
266 error_
= keys::kIncognitoContextError
;
271 if (scope
== kExtensionPrefsScopeIncognitoSessionOnly
&&
272 !GetProfile()->HasOffTheRecordProfile()) {
273 error_
= pref_keys::kIncognitoSessionOnlyErrorMessage
;
277 scoped_refptr
<ContentSettingsStore
> store
=
278 ContentSettingsService::Get(GetProfile())->content_settings_store();
279 store
->SetExtensionContentSetting(extension_id(), primary_pattern
,
280 secondary_pattern
, content_type
,
281 resource_identifier
, setting
, scope
);
285 bool ContentSettingsContentSettingGetResourceIdentifiersFunction::RunAsync() {
286 ContentSettingsType content_type
;
287 EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_
.get(), &content_type
));
289 if (content_type
!= CONTENT_SETTINGS_TYPE_PLUGINS
) {
294 PluginService::GetInstance()->GetPlugins(
295 base::Bind(&ContentSettingsContentSettingGetResourceIdentifiersFunction::
301 void ContentSettingsContentSettingGetResourceIdentifiersFunction::OnGotPlugins(
302 const std::vector
<content::WebPluginInfo
>& plugins
) {
303 PluginFinder
* finder
= PluginFinder::GetInstance();
304 std::set
<std::string
> group_identifiers
;
305 base::ListValue
* list
= new base::ListValue();
306 for (std::vector
<content::WebPluginInfo
>::const_iterator it
= plugins
.begin();
307 it
!= plugins
.end(); ++it
) {
308 scoped_ptr
<PluginMetadata
> plugin_metadata(finder
->GetPluginMetadata(*it
));
309 const std::string
& group_identifier
= plugin_metadata
->identifier();
310 if (group_identifiers
.find(group_identifier
) != group_identifiers
.end())
313 group_identifiers
.insert(group_identifier
);
314 base::DictionaryValue
* dict
= new base::DictionaryValue();
315 dict
->SetString(keys::kIdKey
, group_identifier
);
316 dict
->SetString(keys::kDescriptionKey
, plugin_metadata
->name());
320 BrowserThread::PostTask(
321 BrowserThread::UI
, FROM_HERE
, base::Bind(
322 &ContentSettingsContentSettingGetResourceIdentifiersFunction::
328 } // namespace extensions