Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / content_settings / content_settings_api.cc
blob0030797ab026950e9cab4f087aa0ec9dcef5816f
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"
7 #include <set>
8 #include <vector>
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;
43 namespace {
45 bool RemoveContentType(base::ListValue* args,
46 ContentSettingsType* content_type) {
47 std::string content_type_str;
48 if (!args->GetString(0, &content_type_str))
49 return false;
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);
53 *content_type =
54 extensions::content_settings_helpers::StringToContentSettingsType(
55 content_type_str);
56 return *content_type != CONTENT_SETTINGS_TYPE_DEFAULT;
59 } // namespace
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;
78 incognito = true;
81 if (incognito) {
82 // We don't check incognito permissions here, as an extension should be
83 // always allowed to clear its own settings.
84 } else {
85 // Incognito profiles can't access regular mode ever, they only exist in
86 // split mode.
87 if (GetProfile()->IsOffTheRecord()) {
88 error_ = keys::kIncognitoContextError;
89 return false;
93 scoped_refptr<ContentSettingsStore> store =
94 ContentSettingsService::Get(GetProfile())->content_settings_store();
95 store->ClearContentSettingsForExtension(extension_id(), scope);
97 return true;
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);
111 return false;
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);
120 return false;
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;
133 return false;
136 HostContentSettingsMap* map;
137 content_settings::CookieSettings* cookie_settings;
138 if (incognito) {
139 if (!GetProfile()->HasOffTheRecordProfile()) {
140 // TODO(bauerb): Allow reading incognito content settings
141 // outside of an incognito session.
142 error_ = keys::kIncognitoSessionOnlyError;
143 return false;
145 map = HostContentSettingsMapFactory::GetForProfile(
146 GetProfile()->GetOffTheRecordProfile());
147 cookie_settings = CookieSettingsFactory::GetForProfile(
148 GetProfile()->GetOffTheRecordProfile()).get();
149 } else {
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);
160 } else {
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));
169 SetResult(result);
171 return true;
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,
184 &primary_error);
185 if (!primary_pattern.IsValid()) {
186 error_ = primary_error;
187 return false;
190 ContentSettingsPattern secondary_pattern = ContentSettingsPattern::Wildcard();
191 if (params->details.secondary_pattern.get()) {
192 std::string secondary_error;
193 secondary_pattern =
194 helpers::ParseExtensionPattern(*params->details.secondary_pattern,
195 &secondary_error);
196 if (!secondary_pattern.IsValid()) {
197 error_ = secondary_error;
198 return false;
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";
233 break;
234 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
235 readable_type_name = "camera";
236 break;
237 default:
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());
245 return false;
248 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
249 bool incognito = false;
250 if (params->details.scope ==
251 api::content_settings::SCOPE_INCOGNITO_SESSION_ONLY) {
252 scope = kExtensionPrefsScopeIncognitoSessionOnly;
253 incognito = true;
256 if (incognito) {
257 // Regular profiles can't access incognito unless include_incognito is true.
258 if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
259 error_ = pref_keys::kIncognitoErrorMessage;
260 return false;
262 } else {
263 // Incognito profiles can't access regular mode ever, they only exist in
264 // split mode.
265 if (GetProfile()->IsOffTheRecord()) {
266 error_ = keys::kIncognitoContextError;
267 return false;
271 if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
272 !GetProfile()->HasOffTheRecordProfile()) {
273 error_ = pref_keys::kIncognitoSessionOnlyErrorMessage;
274 return false;
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);
282 return true;
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) {
290 SendResponse(true);
291 return true;
294 PluginService::GetInstance()->GetPlugins(
295 base::Bind(&ContentSettingsContentSettingGetResourceIdentifiersFunction::
296 OnGotPlugins,
297 this));
298 return true;
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())
311 continue;
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());
317 list->Append(dict);
319 SetResult(list);
320 BrowserThread::PostTask(
321 BrowserThread::UI, FROM_HERE, base::Bind(
322 &ContentSettingsContentSettingGetResourceIdentifiersFunction::
323 SendResponse,
324 this,
325 true));
328 } // namespace extensions