Revert 168224 - Update V8 to version 3.15.4.
[chromium-blink-merge.git] / chrome / browser / content_settings / host_content_settings_map.cc
blobc501659eb24b711481584cf1d66f6d5338432695
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/content_settings/host_content_settings_map.h"
7 #include <utility>
9 #include "base/basictypes.h"
10 #include "base/command_line.h"
11 #include "base/stl_util.h"
12 #include "base/string_util.h"
13 #include "base/utf_string_conversions.h"
14 #include "chrome/browser/content_settings/content_settings_custom_extension_provider.h"
15 #include "chrome/browser/content_settings/content_settings_default_provider.h"
16 #include "chrome/browser/content_settings/content_settings_details.h"
17 #include "chrome/browser/content_settings/content_settings_internal_extension_provider.h"
18 #include "chrome/browser/content_settings/content_settings_observable_provider.h"
19 #include "chrome/browser/content_settings/content_settings_policy_provider.h"
20 #include "chrome/browser/content_settings/content_settings_pref_provider.h"
21 #include "chrome/browser/content_settings/content_settings_provider.h"
22 #include "chrome/browser/content_settings/content_settings_rule.h"
23 #include "chrome/browser/content_settings/content_settings_utils.h"
24 #include "chrome/browser/extensions/extension_service.h"
25 #include "chrome/browser/intents/web_intents_util.h"
26 #include "chrome/browser/prefs/pref_service.h"
27 #include "chrome/common/chrome_notification_types.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/content_settings_pattern.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/common/url_constants.h"
32 #include "content/public/browser/browser_thread.h"
33 #include "content/public/browser/notification_service.h"
34 #include "content/public/browser/notification_source.h"
35 #include "content/public/browser/user_metrics.h"
36 #include "content/public/common/content_switches.h"
37 #include "extensions/common/constants.h"
38 #include "googleurl/src/gurl.h"
39 #include "net/base/net_errors.h"
40 #include "net/base/static_cookie_policy.h"
42 using content::BrowserThread;
43 using content::UserMetricsAction;
45 namespace {
47 typedef std::vector<content_settings::Rule> Rules;
49 typedef std::pair<std::string, std::string> StringPair;
51 const char* kProviderNames[] = {
52 "platform_app",
53 "policy",
54 "extension",
55 "preference",
56 "default"
59 content_settings::SettingSource kProviderSourceMap[] = {
60 content_settings::SETTING_SOURCE_EXTENSION,
61 content_settings::SETTING_SOURCE_POLICY,
62 content_settings::SETTING_SOURCE_EXTENSION,
63 content_settings::SETTING_SOURCE_USER,
64 content_settings::SETTING_SOURCE_USER,
66 COMPILE_ASSERT(arraysize(kProviderSourceMap) ==
67 HostContentSettingsMap::NUM_PROVIDER_TYPES,
68 kProviderSourceMap_has_incorrect_size);
70 // Returns true if the |content_type| supports a resource identifier.
71 // Resource identifiers are supported (but not required) for plug-ins.
72 bool SupportsResourceIdentifier(ContentSettingsType content_type) {
73 return content_type == CONTENT_SETTINGS_TYPE_PLUGINS;
76 } // namespace
78 HostContentSettingsMap::HostContentSettingsMap(
79 PrefService* prefs,
80 bool incognito)
81 : prefs_(prefs),
82 is_off_the_record_(incognito) {
83 content_settings::ObservableProvider* policy_provider =
84 new content_settings::PolicyProvider(prefs_);
85 policy_provider->AddObserver(this);
86 content_settings_providers_[POLICY_PROVIDER] = policy_provider;
88 content_settings::ObservableProvider* pref_provider =
89 new content_settings::PrefProvider(prefs_, is_off_the_record_);
90 pref_provider->AddObserver(this);
91 content_settings_providers_[PREF_PROVIDER] = pref_provider;
93 content_settings::ObservableProvider* default_provider =
94 new content_settings::DefaultProvider(prefs_, is_off_the_record_);
95 default_provider->AddObserver(this);
96 content_settings_providers_[DEFAULT_PROVIDER] = default_provider;
98 if (!is_off_the_record_) {
99 // Migrate obsolete preferences.
100 MigrateObsoleteClearOnExitPref();
104 #if defined(ENABLE_EXTENSIONS)
105 void HostContentSettingsMap::RegisterExtensionService(
106 ExtensionService* extension_service) {
107 DCHECK(extension_service);
108 DCHECK(!content_settings_providers_[INTERNAL_EXTENSION_PROVIDER]);
109 DCHECK(!content_settings_providers_[CUSTOM_EXTENSION_PROVIDER]);
111 content_settings::InternalExtensionProvider* internal_extension_provider =
112 new content_settings::InternalExtensionProvider(extension_service);
113 internal_extension_provider->AddObserver(this);
114 content_settings_providers_[INTERNAL_EXTENSION_PROVIDER] =
115 internal_extension_provider;
117 content_settings::ObservableProvider* custom_extension_provider =
118 new content_settings::CustomExtensionProvider(
119 extension_service->GetContentSettingsStore(),
120 is_off_the_record_);
121 custom_extension_provider->AddObserver(this);
122 content_settings_providers_[CUSTOM_EXTENSION_PROVIDER] =
123 custom_extension_provider;
125 OnContentSettingChanged(ContentSettingsPattern(),
126 ContentSettingsPattern(),
127 CONTENT_SETTINGS_TYPE_DEFAULT,
128 "");
130 #endif
132 // static
133 void HostContentSettingsMap::RegisterUserPrefs(PrefService* prefs) {
134 prefs->RegisterIntegerPref(prefs::kContentSettingsWindowLastTabIndex,
136 PrefService::UNSYNCABLE_PREF);
137 prefs->RegisterIntegerPref(prefs::kContentSettingsDefaultWhitelistVersion,
138 0, PrefService::SYNCABLE_PREF);
139 prefs->RegisterBooleanPref(prefs::kContentSettingsClearOnExitMigrated,
140 false, PrefService::SYNCABLE_PREF);
142 // Register the prefs for the content settings providers.
143 content_settings::DefaultProvider::RegisterUserPrefs(prefs);
144 content_settings::PrefProvider::RegisterUserPrefs(prefs);
145 content_settings::PolicyProvider::RegisterUserPrefs(prefs);
148 ContentSetting HostContentSettingsMap::GetDefaultContentSettingFromProvider(
149 ContentSettingsType content_type,
150 content_settings::ProviderInterface* provider) const {
151 scoped_ptr<content_settings::RuleIterator> rule_iterator(
152 provider->GetRuleIterator(content_type, "", false));
154 ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard();
155 while (rule_iterator->HasNext()) {
156 content_settings::Rule rule = rule_iterator->Next();
157 if (rule.primary_pattern == wildcard &&
158 rule.secondary_pattern == wildcard) {
159 return content_settings::ValueToContentSetting(rule.value.get());
162 return CONTENT_SETTING_DEFAULT;
165 ContentSetting HostContentSettingsMap::GetDefaultContentSetting(
166 ContentSettingsType content_type,
167 std::string* provider_id) const {
168 // Iterate through the list of providers and return the first non-NULL value
169 // that matches |primary_url| and |secondary_url|.
170 for (ConstProviderIterator provider = content_settings_providers_.begin();
171 provider != content_settings_providers_.end();
172 ++provider) {
173 if (provider->first == PREF_PROVIDER)
174 continue;
175 ContentSetting default_setting =
176 GetDefaultContentSettingFromProvider(content_type, provider->second);
177 if (default_setting != CONTENT_SETTING_DEFAULT) {
178 if (provider_id)
179 *provider_id = kProviderNames[provider->first];
180 return default_setting;
184 // The method GetDefaultContentSetting always has to return an explicit
185 // value that is to be used as default. We here rely on the
186 // DefaultProvider to always provide a value.
187 NOTREACHED();
188 return CONTENT_SETTING_DEFAULT;
191 ContentSetting HostContentSettingsMap::GetContentSetting(
192 const GURL& primary_url,
193 const GURL& secondary_url,
194 ContentSettingsType content_type,
195 const std::string& resource_identifier) const {
196 DCHECK(!ContentTypeHasCompoundValue(content_type));
197 scoped_ptr<base::Value> value(GetWebsiteSetting(
198 primary_url, secondary_url, content_type, resource_identifier, NULL));
199 return content_settings::ValueToContentSetting(value.get());
202 void HostContentSettingsMap::GetSettingsForOneType(
203 ContentSettingsType content_type,
204 const std::string& resource_identifier,
205 ContentSettingsForOneType* settings) const {
206 DCHECK(SupportsResourceIdentifier(content_type) ||
207 resource_identifier.empty());
208 DCHECK(settings);
210 settings->clear();
211 for (ConstProviderIterator provider = content_settings_providers_.begin();
212 provider != content_settings_providers_.end();
213 ++provider) {
214 // For each provider, iterate first the incognito-specific rules, then the
215 // normal rules.
216 if (is_off_the_record_) {
217 AddSettingsForOneType(provider->second,
218 provider->first,
219 content_type,
220 resource_identifier,
221 settings,
222 true);
224 AddSettingsForOneType(provider->second,
225 provider->first,
226 content_type,
227 resource_identifier,
228 settings,
229 false);
233 void HostContentSettingsMap::SetDefaultContentSetting(
234 ContentSettingsType content_type,
235 ContentSetting setting) {
236 DCHECK(IsSettingAllowedForType(prefs_, setting, content_type));
238 base::Value* value = NULL;
239 if (setting != CONTENT_SETTING_DEFAULT)
240 value = Value::CreateIntegerValue(setting);
241 SetWebsiteSetting(
242 ContentSettingsPattern::Wildcard(),
243 ContentSettingsPattern::Wildcard(),
244 content_type,
245 std::string(),
246 value);
249 void HostContentSettingsMap::SetWebsiteSetting(
250 const ContentSettingsPattern& primary_pattern,
251 const ContentSettingsPattern& secondary_pattern,
252 ContentSettingsType content_type,
253 const std::string& resource_identifier,
254 base::Value* value) {
255 DCHECK(IsValueAllowedForType(prefs_, value, content_type));
256 DCHECK(SupportsResourceIdentifier(content_type) ||
257 resource_identifier.empty());
258 for (ProviderIterator provider = content_settings_providers_.begin();
259 provider != content_settings_providers_.end();
260 ++provider) {
261 if (provider->second->SetWebsiteSetting(primary_pattern,
262 secondary_pattern,
263 content_type,
264 resource_identifier,
265 value)) {
266 return;
269 NOTREACHED();
272 void HostContentSettingsMap::SetContentSetting(
273 const ContentSettingsPattern& primary_pattern,
274 const ContentSettingsPattern& secondary_pattern,
275 ContentSettingsType content_type,
276 const std::string& resource_identifier,
277 ContentSetting setting) {
278 DCHECK(!ContentTypeHasCompoundValue(content_type));
279 base::Value* value = NULL;
280 if (setting != CONTENT_SETTING_DEFAULT)
281 value = Value::CreateIntegerValue(setting);
282 SetWebsiteSetting(primary_pattern,
283 secondary_pattern,
284 content_type,
285 resource_identifier,
286 value);
289 void HostContentSettingsMap::AddExceptionForURL(
290 const GURL& primary_url,
291 const GURL& secondary_url,
292 ContentSettingsType content_type,
293 const std::string& resource_identifier,
294 ContentSetting setting) {
295 // TODO(markusheintz): Until the UI supports pattern pairs, both urls must
296 // match.
297 DCHECK(primary_url == secondary_url);
298 DCHECK(!ContentTypeHasCompoundValue(content_type));
300 // Make sure there is no entry that would override the pattern we are about
301 // to insert for exactly this URL.
302 SetContentSetting(ContentSettingsPattern::FromURLNoWildcard(primary_url),
303 ContentSettingsPattern::Wildcard(),
304 content_type,
305 resource_identifier,
306 CONTENT_SETTING_DEFAULT);
308 SetContentSetting(ContentSettingsPattern::FromURL(primary_url),
309 ContentSettingsPattern::Wildcard(),
310 content_type,
311 resource_identifier,
312 setting);
315 void HostContentSettingsMap::ClearSettingsForOneType(
316 ContentSettingsType content_type) {
317 for (ProviderIterator provider = content_settings_providers_.begin();
318 provider != content_settings_providers_.end();
319 ++provider) {
320 provider->second->ClearAllContentSettingsRules(content_type);
324 bool HostContentSettingsMap::IsValueAllowedForType(
325 PrefService* prefs, const base::Value* value, ContentSettingsType type) {
326 return ContentTypeHasCompoundValue(type) || IsSettingAllowedForType(
327 prefs, content_settings::ValueToContentSetting(value), type);
330 // static
331 bool HostContentSettingsMap::IsSettingAllowedForType(
332 PrefService* prefs,
333 ContentSetting setting,
334 ContentSettingsType content_type) {
335 // Intents content settings are hidden behind a switch for now.
336 if (content_type == CONTENT_SETTINGS_TYPE_INTENTS) {
337 if (!web_intents::IsWebIntentsEnabled(prefs))
338 return false;
341 // We don't yet support stored content settings for mixed scripting.
342 if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT)
343 return false;
345 // BLOCK semantics are not implemented for fullscreen.
346 if (content_type == CONTENT_SETTINGS_TYPE_FULLSCREEN &&
347 setting == CONTENT_SETTING_BLOCK) {
348 return false;
351 // DEFAULT, ALLOW and BLOCK are always allowed.
352 if (setting == CONTENT_SETTING_DEFAULT ||
353 setting == CONTENT_SETTING_ALLOW ||
354 setting == CONTENT_SETTING_BLOCK) {
355 return true;
357 switch (content_type) {
358 case CONTENT_SETTINGS_TYPE_COOKIES:
359 return setting == CONTENT_SETTING_SESSION_ONLY;
360 case CONTENT_SETTINGS_TYPE_PLUGINS:
361 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
362 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
363 case CONTENT_SETTINGS_TYPE_INTENTS:
364 case CONTENT_SETTINGS_TYPE_MOUSELOCK:
365 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
366 case CONTENT_SETTINGS_TYPE_PPAPI_BROKER:
367 return setting == CONTENT_SETTING_ASK;
368 default:
369 return false;
373 // static
374 bool HostContentSettingsMap::ContentTypeHasCompoundValue(
375 ContentSettingsType type) {
376 // Values for content type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE are
377 // of type dictionary/map. Compound types like dictionaries can't be mapped to
378 // the type |ContentSetting|.
379 return (type == CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE ||
380 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM);
383 void HostContentSettingsMap::OnContentSettingChanged(
384 const ContentSettingsPattern& primary_pattern,
385 const ContentSettingsPattern& secondary_pattern,
386 ContentSettingsType content_type,
387 std::string resource_identifier) {
388 const ContentSettingsDetails details(primary_pattern,
389 secondary_pattern,
390 content_type,
391 resource_identifier);
392 content::NotificationService::current()->Notify(
393 chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED,
394 content::Source<HostContentSettingsMap>(this),
395 content::Details<const ContentSettingsDetails>(&details));
398 HostContentSettingsMap::~HostContentSettingsMap() {
399 DCHECK(!prefs_);
400 STLDeleteValues(&content_settings_providers_);
403 void HostContentSettingsMap::ShutdownOnUIThread() {
404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
405 DCHECK(prefs_);
406 prefs_ = NULL;
407 for (ProviderIterator it = content_settings_providers_.begin();
408 it != content_settings_providers_.end();
409 ++it) {
410 it->second->ShutdownOnUIThread();
414 void HostContentSettingsMap::MigrateObsoleteClearOnExitPref() {
415 // Don't migrate more than once.
416 if (prefs_->HasPrefPath(prefs::kContentSettingsClearOnExitMigrated) &&
417 prefs_->GetBoolean(prefs::kContentSettingsClearOnExitMigrated)) {
418 return;
421 if (!prefs_->GetBoolean(prefs::kClearSiteDataOnExit)) {
422 // Nothing to be done
423 prefs_->SetBoolean(prefs::kContentSettingsClearOnExitMigrated, true);
424 return;
427 // Change the default cookie settings:
428 // old new
429 // ---------------- ----------------
430 // ALLOW SESSION_ONLY
431 // SESSION_ONLY SESSION_ONLY
432 // BLOCK BLOCK
433 ContentSetting default_setting = GetDefaultContentSettingFromProvider(
434 CONTENT_SETTINGS_TYPE_COOKIES,
435 content_settings_providers_[DEFAULT_PROVIDER]);
436 if (default_setting == CONTENT_SETTING_ALLOW) {
437 SetDefaultContentSetting(
438 CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_SESSION_ONLY);
441 // Change the exceptions using the same rules.
442 ContentSettingsForOneType exceptions;
443 AddSettingsForOneType(content_settings_providers_[PREF_PROVIDER],
444 PREF_PROVIDER,
445 CONTENT_SETTINGS_TYPE_COOKIES,
447 &exceptions,
448 false);
449 for (ContentSettingsForOneType::iterator it = exceptions.begin();
450 it != exceptions.end(); ++it) {
451 if (it->setting != CONTENT_SETTING_ALLOW)
452 continue;
453 SetWebsiteSetting(
454 it->primary_pattern,
455 it->secondary_pattern,
456 CONTENT_SETTINGS_TYPE_COOKIES,
458 Value::CreateIntegerValue(CONTENT_SETTING_SESSION_ONLY));
461 prefs_->SetBoolean(prefs::kContentSettingsClearOnExitMigrated, true);
465 void HostContentSettingsMap::AddSettingsForOneType(
466 const content_settings::ProviderInterface* provider,
467 ProviderType provider_type,
468 ContentSettingsType content_type,
469 const std::string& resource_identifier,
470 ContentSettingsForOneType* settings,
471 bool incognito) const {
472 scoped_ptr<content_settings::RuleIterator> rule_iterator(
473 provider->GetRuleIterator(content_type,
474 resource_identifier,
475 incognito));
476 while (rule_iterator->HasNext()) {
477 const content_settings::Rule& rule = rule_iterator->Next();
478 ContentSetting setting_value = CONTENT_SETTING_DEFAULT;
479 // TODO(bauerb): Return rules as a list of values, not content settings.
480 // Handle the case using compound values for its exceptions and arbitrary
481 // values for its default setting. Here we assume all the exceptions
482 // are granted as |CONTENT_SETTING_ALLOW|.
483 if (ContentTypeHasCompoundValue(content_type) &&
484 rule.value.get() &&
485 rule.primary_pattern != ContentSettingsPattern::Wildcard()) {
486 setting_value = CONTENT_SETTING_ALLOW;
487 } else {
488 setting_value = content_settings::ValueToContentSetting(rule.value.get());
490 settings->push_back(ContentSettingPatternSource(
491 rule.primary_pattern, rule.secondary_pattern,
492 setting_value,
493 kProviderNames[provider_type],
494 incognito));
498 bool HostContentSettingsMap::ShouldAllowAllContent(
499 const GURL& primary_url,
500 const GURL& secondary_url,
501 ContentSettingsType content_type) {
502 if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS ||
503 content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
504 return false;
506 if (secondary_url.SchemeIs(chrome::kChromeUIScheme) &&
507 content_type == CONTENT_SETTINGS_TYPE_COOKIES &&
508 primary_url.SchemeIsSecure()) {
509 return true;
511 if (primary_url.SchemeIs(extensions::kExtensionScheme)) {
512 return content_type != CONTENT_SETTINGS_TYPE_PLUGINS &&
513 (content_type != CONTENT_SETTINGS_TYPE_COOKIES ||
514 secondary_url.SchemeIs(extensions::kExtensionScheme));
516 return primary_url.SchemeIs(chrome::kChromeDevToolsScheme) ||
517 primary_url.SchemeIs(chrome::kChromeInternalScheme) ||
518 primary_url.SchemeIs(chrome::kChromeUIScheme);
521 base::Value* HostContentSettingsMap::GetWebsiteSetting(
522 const GURL& primary_url,
523 const GURL& secondary_url,
524 ContentSettingsType content_type,
525 const std::string& resource_identifier,
526 content_settings::SettingInfo* info) const {
527 DCHECK(SupportsResourceIdentifier(content_type) ||
528 resource_identifier.empty());
530 // Check if the scheme of the requesting url is whitelisted.
531 if (ShouldAllowAllContent(primary_url, secondary_url, content_type)) {
532 if (info) {
533 info->source = content_settings::SETTING_SOURCE_WHITELIST;
534 info->primary_pattern = ContentSettingsPattern::Wildcard();
535 info->secondary_pattern = ContentSettingsPattern::Wildcard();
537 return Value::CreateIntegerValue(CONTENT_SETTING_ALLOW);
540 ContentSettingsPattern* primary_pattern = NULL;
541 ContentSettingsPattern* secondary_pattern = NULL;
542 if (info) {
543 primary_pattern = &info->primary_pattern;
544 secondary_pattern = &info->secondary_pattern;
547 // The list of |content_settings_providers_| is ordered according to their
548 // precedence.
549 for (ConstProviderIterator provider = content_settings_providers_.begin();
550 provider != content_settings_providers_.end();
551 ++provider) {
552 base::Value* value = content_settings::GetContentSettingValueAndPatterns(
553 provider->second, primary_url, secondary_url, content_type,
554 resource_identifier, is_off_the_record_,
555 primary_pattern, secondary_pattern);
556 if (value) {
557 if (info)
558 info->source = kProviderSourceMap[provider->first];
559 return value;
563 if (info) {
564 info->source = content_settings::SETTING_SOURCE_NONE;
565 info->primary_pattern = ContentSettingsPattern();
566 info->secondary_pattern = ContentSettingsPattern();
568 return NULL;
571 // static
572 HostContentSettingsMap::ProviderType
573 HostContentSettingsMap::GetProviderTypeFromSource(
574 const std::string& source) {
575 for (size_t i = 0; i < arraysize(kProviderNames); ++i) {
576 if (source == kProviderNames[i])
577 return static_cast<ProviderType>(i);
580 NOTREACHED();
581 return DEFAULT_PROVIDER;