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"
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
;
47 typedef std::vector
<content_settings::Rule
> Rules
;
49 typedef std::pair
<std::string
, std::string
> StringPair
;
51 const char* kProviderNames
[] = {
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
;
78 HostContentSettingsMap::HostContentSettingsMap(
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(),
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
,
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();
173 if (provider
->first
== PREF_PROVIDER
)
175 ContentSetting default_setting
=
176 GetDefaultContentSettingFromProvider(content_type
, provider
->second
);
177 if (default_setting
!= CONTENT_SETTING_DEFAULT
) {
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.
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());
211 for (ConstProviderIterator provider
= content_settings_providers_
.begin();
212 provider
!= content_settings_providers_
.end();
214 // For each provider, iterate first the incognito-specific rules, then the
216 if (is_off_the_record_
) {
217 AddSettingsForOneType(provider
->second
,
224 AddSettingsForOneType(provider
->second
,
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
);
242 ContentSettingsPattern::Wildcard(),
243 ContentSettingsPattern::Wildcard(),
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();
261 if (provider
->second
->SetWebsiteSetting(primary_pattern
,
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
,
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
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(),
306 CONTENT_SETTING_DEFAULT
);
308 SetContentSetting(ContentSettingsPattern::FromURL(primary_url
),
309 ContentSettingsPattern::Wildcard(),
315 void HostContentSettingsMap::ClearSettingsForOneType(
316 ContentSettingsType content_type
) {
317 for (ProviderIterator provider
= content_settings_providers_
.begin();
318 provider
!= content_settings_providers_
.end();
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
);
331 bool HostContentSettingsMap::IsSettingAllowedForType(
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
))
341 // We don't yet support stored content settings for mixed scripting.
342 if (content_type
== CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
)
345 // BLOCK semantics are not implemented for fullscreen.
346 if (content_type
== CONTENT_SETTINGS_TYPE_FULLSCREEN
&&
347 setting
== CONTENT_SETTING_BLOCK
) {
351 // DEFAULT, ALLOW and BLOCK are always allowed.
352 if (setting
== CONTENT_SETTING_DEFAULT
||
353 setting
== CONTENT_SETTING_ALLOW
||
354 setting
== CONTENT_SETTING_BLOCK
) {
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
;
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
,
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() {
400 STLDeleteValues(&content_settings_providers_
);
403 void HostContentSettingsMap::ShutdownOnUIThread() {
404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
407 for (ProviderIterator it
= content_settings_providers_
.begin();
408 it
!= content_settings_providers_
.end();
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
)) {
421 if (!prefs_
->GetBoolean(prefs::kClearSiteDataOnExit
)) {
422 // Nothing to be done
423 prefs_
->SetBoolean(prefs::kContentSettingsClearOnExitMigrated
, true);
427 // Change the default cookie settings:
429 // ---------------- ----------------
430 // ALLOW SESSION_ONLY
431 // SESSION_ONLY SESSION_ONLY
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
],
445 CONTENT_SETTINGS_TYPE_COOKIES
,
449 for (ContentSettingsForOneType::iterator it
= exceptions
.begin();
450 it
!= exceptions
.end(); ++it
) {
451 if (it
->setting
!= CONTENT_SETTING_ALLOW
)
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
,
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
) &&
485 rule
.primary_pattern
!= ContentSettingsPattern::Wildcard()) {
486 setting_value
= CONTENT_SETTING_ALLOW
;
488 setting_value
= content_settings::ValueToContentSetting(rule
.value
.get());
490 settings
->push_back(ContentSettingPatternSource(
491 rule
.primary_pattern
, rule
.secondary_pattern
,
493 kProviderNames
[provider_type
],
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
) {
506 if (secondary_url
.SchemeIs(chrome::kChromeUIScheme
) &&
507 content_type
== CONTENT_SETTINGS_TYPE_COOKIES
&&
508 primary_url
.SchemeIsSecure()) {
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
)) {
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
;
543 primary_pattern
= &info
->primary_pattern
;
544 secondary_pattern
= &info
->secondary_pattern
;
547 // The list of |content_settings_providers_| is ordered according to their
549 for (ConstProviderIterator provider
= content_settings_providers_
.begin();
550 provider
!= content_settings_providers_
.end();
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
);
558 info
->source
= kProviderSourceMap
[provider
->first
];
564 info
->source
= content_settings::SETTING_SOURCE_NONE
;
565 info
->primary_pattern
= ContentSettingsPattern();
566 info
->secondary_pattern
= ContentSettingsPattern();
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
);
581 return DEFAULT_PROVIDER
;