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/prefs/pref_service.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/content_settings/content_settings_custom_extension_provider.h"
17 #include "chrome/browser/content_settings/content_settings_default_provider.h"
18 #include "chrome/browser/content_settings/content_settings_details.h"
19 #include "chrome/browser/content_settings/content_settings_internal_extension_provider.h"
20 #include "chrome/browser/content_settings/content_settings_observable_provider.h"
21 #include "chrome/browser/content_settings/content_settings_policy_provider.h"
22 #include "chrome/browser/content_settings/content_settings_pref_provider.h"
23 #include "chrome/browser/content_settings/content_settings_provider.h"
24 #include "chrome/browser/content_settings/content_settings_rule.h"
25 #include "chrome/browser/content_settings/content_settings_utils.h"
26 #include "chrome/browser/extensions/extension_service.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/content_settings_pattern.h"
29 #include "chrome/common/pref_names.h"
30 #include "chrome/common/url_constants.h"
31 #include "components/user_prefs/pref_registry_syncable.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 "net/base/net_errors.h"
39 #include "net/base/static_cookie_policy.h"
42 using base::UserMetricsAction
;
43 using content::BrowserThread
;
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 used_from_thread_id_(base::PlatformThread::CurrentId()),
85 is_off_the_record_(incognito
) {
86 content_settings::ObservableProvider
* policy_provider
=
87 new content_settings::PolicyProvider(prefs_
);
88 policy_provider
->AddObserver(this);
89 content_settings_providers_
[POLICY_PROVIDER
] = policy_provider
;
91 content_settings::ObservableProvider
* pref_provider
=
92 new content_settings::PrefProvider(prefs_
, is_off_the_record_
);
93 pref_provider
->AddObserver(this);
94 content_settings_providers_
[PREF_PROVIDER
] = pref_provider
;
96 content_settings::ObservableProvider
* default_provider
=
97 new content_settings::DefaultProvider(prefs_
, is_off_the_record_
);
98 default_provider
->AddObserver(this);
99 content_settings_providers_
[DEFAULT_PROVIDER
] = default_provider
;
101 if (!is_off_the_record_
) {
102 // Migrate obsolete preferences.
103 MigrateObsoleteClearOnExitPref();
107 #if defined(ENABLE_EXTENSIONS)
108 void HostContentSettingsMap::RegisterExtensionService(
109 ExtensionService
* extension_service
) {
110 DCHECK(extension_service
);
111 DCHECK(!content_settings_providers_
[INTERNAL_EXTENSION_PROVIDER
]);
112 DCHECK(!content_settings_providers_
[CUSTOM_EXTENSION_PROVIDER
]);
114 content_settings::InternalExtensionProvider
* internal_extension_provider
=
115 new content_settings::InternalExtensionProvider(extension_service
);
116 internal_extension_provider
->AddObserver(this);
117 content_settings_providers_
[INTERNAL_EXTENSION_PROVIDER
] =
118 internal_extension_provider
;
120 content_settings::ObservableProvider
* custom_extension_provider
=
121 new content_settings::CustomExtensionProvider(
122 extension_service
->GetContentSettingsStore(),
124 custom_extension_provider
->AddObserver(this);
125 content_settings_providers_
[CUSTOM_EXTENSION_PROVIDER
] =
126 custom_extension_provider
;
129 DCHECK(used_from_thread_id_
!= base::kInvalidThreadId
)
130 << "Used from multiple threads before initialization complete.";
133 OnContentSettingChanged(ContentSettingsPattern(),
134 ContentSettingsPattern(),
135 CONTENT_SETTINGS_TYPE_DEFAULT
,
141 void HostContentSettingsMap::RegisterProfilePrefs(
142 user_prefs::PrefRegistrySyncable
* registry
) {
143 registry
->RegisterIntegerPref(
144 prefs::kContentSettingsWindowLastTabIndex
,
146 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
147 registry
->RegisterIntegerPref(
148 prefs::kContentSettingsDefaultWhitelistVersion
,
150 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF
);
151 registry
->RegisterBooleanPref(
152 prefs::kContentSettingsClearOnExitMigrated
,
154 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF
);
156 // Register the prefs for the content settings providers.
157 content_settings::DefaultProvider::RegisterProfilePrefs(registry
);
158 content_settings::PrefProvider::RegisterProfilePrefs(registry
);
159 content_settings::PolicyProvider::RegisterProfilePrefs(registry
);
162 ContentSetting
HostContentSettingsMap::GetDefaultContentSettingFromProvider(
163 ContentSettingsType content_type
,
164 content_settings::ProviderInterface
* provider
) const {
165 scoped_ptr
<content_settings::RuleIterator
> rule_iterator(
166 provider
->GetRuleIterator(content_type
, std::string(), false));
168 ContentSettingsPattern wildcard
= ContentSettingsPattern::Wildcard();
169 while (rule_iterator
->HasNext()) {
170 content_settings::Rule rule
= rule_iterator
->Next();
171 if (rule
.primary_pattern
== wildcard
&&
172 rule
.secondary_pattern
== wildcard
) {
173 return content_settings::ValueToContentSetting(rule
.value
.get());
176 return CONTENT_SETTING_DEFAULT
;
179 ContentSetting
HostContentSettingsMap::GetDefaultContentSetting(
180 ContentSettingsType content_type
,
181 std::string
* provider_id
) const {
182 UsedContentSettingsProviders();
184 // Iterate through the list of providers and return the first non-NULL value
185 // that matches |primary_url| and |secondary_url|.
186 for (ConstProviderIterator provider
= content_settings_providers_
.begin();
187 provider
!= content_settings_providers_
.end();
189 if (provider
->first
== PREF_PROVIDER
)
191 ContentSetting default_setting
=
192 GetDefaultContentSettingFromProvider(content_type
, provider
->second
);
193 if (default_setting
!= CONTENT_SETTING_DEFAULT
) {
195 *provider_id
= kProviderNames
[provider
->first
];
196 return default_setting
;
200 // The method GetDefaultContentSetting always has to return an explicit
201 // value that is to be used as default. We here rely on the
202 // DefaultProvider to always provide a value.
204 return CONTENT_SETTING_DEFAULT
;
207 ContentSetting
HostContentSettingsMap::GetContentSetting(
208 const GURL
& primary_url
,
209 const GURL
& secondary_url
,
210 ContentSettingsType content_type
,
211 const std::string
& resource_identifier
) const {
212 DCHECK(!ContentTypeHasCompoundValue(content_type
));
213 scoped_ptr
<base::Value
> value(GetWebsiteSetting(
214 primary_url
, secondary_url
, content_type
, resource_identifier
, NULL
));
215 return content_settings::ValueToContentSetting(value
.get());
218 void HostContentSettingsMap::GetSettingsForOneType(
219 ContentSettingsType content_type
,
220 const std::string
& resource_identifier
,
221 ContentSettingsForOneType
* settings
) const {
222 DCHECK(SupportsResourceIdentifier(content_type
) ||
223 resource_identifier
.empty());
225 UsedContentSettingsProviders();
228 for (ConstProviderIterator provider
= content_settings_providers_
.begin();
229 provider
!= content_settings_providers_
.end();
231 // For each provider, iterate first the incognito-specific rules, then the
233 if (is_off_the_record_
) {
234 AddSettingsForOneType(provider
->second
,
241 AddSettingsForOneType(provider
->second
,
250 void HostContentSettingsMap::SetDefaultContentSetting(
251 ContentSettingsType content_type
,
252 ContentSetting setting
) {
253 DCHECK(IsSettingAllowedForType(prefs_
, setting
, content_type
));
255 base::Value
* value
= NULL
;
256 if (setting
!= CONTENT_SETTING_DEFAULT
)
257 value
= base::Value::CreateIntegerValue(setting
);
259 ContentSettingsPattern::Wildcard(),
260 ContentSettingsPattern::Wildcard(),
266 void HostContentSettingsMap::SetWebsiteSetting(
267 const ContentSettingsPattern
& primary_pattern
,
268 const ContentSettingsPattern
& secondary_pattern
,
269 ContentSettingsType content_type
,
270 const std::string
& resource_identifier
,
271 base::Value
* value
) {
272 DCHECK(IsValueAllowedForType(prefs_
, value
, content_type
));
273 DCHECK(SupportsResourceIdentifier(content_type
) ||
274 resource_identifier
.empty());
275 UsedContentSettingsProviders();
277 for (ProviderIterator provider
= content_settings_providers_
.begin();
278 provider
!= content_settings_providers_
.end();
280 if (provider
->second
->SetWebsiteSetting(primary_pattern
,
291 void HostContentSettingsMap::SetContentSetting(
292 const ContentSettingsPattern
& primary_pattern
,
293 const ContentSettingsPattern
& secondary_pattern
,
294 ContentSettingsType content_type
,
295 const std::string
& resource_identifier
,
296 ContentSetting setting
) {
297 DCHECK(!ContentTypeHasCompoundValue(content_type
));
298 base::Value
* value
= NULL
;
299 if (setting
!= CONTENT_SETTING_DEFAULT
)
300 value
= base::Value::CreateIntegerValue(setting
);
301 SetWebsiteSetting(primary_pattern
,
308 void HostContentSettingsMap::AddExceptionForURL(
309 const GURL
& primary_url
,
310 const GURL
& secondary_url
,
311 ContentSettingsType content_type
,
312 ContentSetting setting
) {
313 // TODO(markusheintz): Until the UI supports pattern pairs, both urls must
315 DCHECK(primary_url
== secondary_url
);
316 DCHECK(!ContentTypeHasCompoundValue(content_type
));
318 // Make sure there is no entry that would override the pattern we are about
319 // to insert for exactly this URL.
320 SetContentSetting(ContentSettingsPattern::FromURLNoWildcard(primary_url
),
321 ContentSettingsPattern::Wildcard(),
324 CONTENT_SETTING_DEFAULT
);
326 SetContentSetting(ContentSettingsPattern::FromURL(primary_url
),
327 ContentSettingsPattern::Wildcard(),
333 void HostContentSettingsMap::ClearSettingsForOneType(
334 ContentSettingsType content_type
) {
335 UsedContentSettingsProviders();
336 for (ProviderIterator provider
= content_settings_providers_
.begin();
337 provider
!= content_settings_providers_
.end();
339 provider
->second
->ClearAllContentSettingsRules(content_type
);
343 bool HostContentSettingsMap::IsValueAllowedForType(
344 PrefService
* prefs
, const base::Value
* value
, ContentSettingsType type
) {
345 return ContentTypeHasCompoundValue(type
) || IsSettingAllowedForType(
346 prefs
, content_settings::ValueToContentSetting(value
), type
);
350 bool HostContentSettingsMap::IsSettingAllowedForType(
352 ContentSetting setting
,
353 ContentSettingsType content_type
) {
354 // We don't yet support stored content settings for mixed scripting.
355 if (content_type
== CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
)
358 // BLOCK semantics are not implemented for fullscreen.
359 if (content_type
== CONTENT_SETTINGS_TYPE_FULLSCREEN
&&
360 setting
== CONTENT_SETTING_BLOCK
) {
364 // We don't support ALLOW for media default setting.
365 if (content_type
== CONTENT_SETTINGS_TYPE_MEDIASTREAM
&&
366 setting
== CONTENT_SETTING_ALLOW
) {
370 // DEFAULT, ALLOW and BLOCK are always allowed.
371 if (setting
== CONTENT_SETTING_DEFAULT
||
372 setting
== CONTENT_SETTING_ALLOW
||
373 setting
== CONTENT_SETTING_BLOCK
) {
376 switch (content_type
) {
377 case CONTENT_SETTINGS_TYPE_COOKIES
:
378 return setting
== CONTENT_SETTING_SESSION_ONLY
;
379 case CONTENT_SETTINGS_TYPE_PLUGINS
:
380 case CONTENT_SETTINGS_TYPE_GEOLOCATION
:
381 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS
:
382 case CONTENT_SETTINGS_TYPE_MOUSELOCK
:
383 case CONTENT_SETTINGS_TYPE_MEDIASTREAM
:
384 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
:
385 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
:
386 case CONTENT_SETTINGS_TYPE_PPAPI_BROKER
:
387 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
:
388 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX
:
389 return setting
== CONTENT_SETTING_ASK
;
396 bool HostContentSettingsMap::ContentTypeHasCompoundValue(
397 ContentSettingsType type
) {
398 // Values for content type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE and
399 // CONTENT_SETTINGS_TYPE_MEDIASTREAM are of type dictionary/map. Compound
400 // types like dictionaries can't be mapped to the type |ContentSetting|.
401 return (type
== CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE
||
402 type
== CONTENT_SETTINGS_TYPE_MEDIASTREAM
);
405 void HostContentSettingsMap::OnContentSettingChanged(
406 const ContentSettingsPattern
& primary_pattern
,
407 const ContentSettingsPattern
& secondary_pattern
,
408 ContentSettingsType content_type
,
409 std::string resource_identifier
) {
410 const ContentSettingsDetails
details(primary_pattern
,
413 resource_identifier
);
414 content::NotificationService::current()->Notify(
415 chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED
,
416 content::Source
<HostContentSettingsMap
>(this),
417 content::Details
<const ContentSettingsDetails
>(&details
));
420 HostContentSettingsMap::~HostContentSettingsMap() {
422 STLDeleteValues(&content_settings_providers_
);
425 void HostContentSettingsMap::ShutdownOnUIThread() {
426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
429 for (ProviderIterator it
= content_settings_providers_
.begin();
430 it
!= content_settings_providers_
.end();
432 it
->second
->ShutdownOnUIThread();
436 void HostContentSettingsMap::MigrateObsoleteClearOnExitPref() {
437 // Don't migrate more than once.
438 if (prefs_
->HasPrefPath(prefs::kContentSettingsClearOnExitMigrated
) &&
439 prefs_
->GetBoolean(prefs::kContentSettingsClearOnExitMigrated
)) {
443 if (!prefs_
->GetBoolean(prefs::kClearSiteDataOnExit
)) {
444 // Nothing to be done
445 prefs_
->SetBoolean(prefs::kContentSettingsClearOnExitMigrated
, true);
449 // Change the default cookie settings:
451 // ---------------- ----------------
452 // ALLOW SESSION_ONLY
453 // SESSION_ONLY SESSION_ONLY
455 ContentSetting default_setting
= GetDefaultContentSettingFromProvider(
456 CONTENT_SETTINGS_TYPE_COOKIES
,
457 content_settings_providers_
[DEFAULT_PROVIDER
]);
458 if (default_setting
== CONTENT_SETTING_ALLOW
) {
459 SetDefaultContentSetting(
460 CONTENT_SETTINGS_TYPE_COOKIES
, CONTENT_SETTING_SESSION_ONLY
);
463 // Change the exceptions using the same rules.
464 ContentSettingsForOneType exceptions
;
465 AddSettingsForOneType(content_settings_providers_
[PREF_PROVIDER
],
467 CONTENT_SETTINGS_TYPE_COOKIES
,
471 for (ContentSettingsForOneType::iterator it
= exceptions
.begin();
472 it
!= exceptions
.end(); ++it
) {
473 if (it
->setting
!= CONTENT_SETTING_ALLOW
)
475 SetWebsiteSetting(it
->primary_pattern
,
476 it
->secondary_pattern
,
477 CONTENT_SETTINGS_TYPE_COOKIES
,
479 base::Value::CreateIntegerValue(
480 CONTENT_SETTING_SESSION_ONLY
));
483 prefs_
->SetBoolean(prefs::kContentSettingsClearOnExitMigrated
, true);
486 void HostContentSettingsMap::AddSettingsForOneType(
487 const content_settings::ProviderInterface
* provider
,
488 ProviderType provider_type
,
489 ContentSettingsType content_type
,
490 const std::string
& resource_identifier
,
491 ContentSettingsForOneType
* settings
,
492 bool incognito
) const {
493 scoped_ptr
<content_settings::RuleIterator
> rule_iterator(
494 provider
->GetRuleIterator(content_type
,
497 while (rule_iterator
->HasNext()) {
498 const content_settings::Rule
& rule
= rule_iterator
->Next();
499 ContentSetting setting_value
= CONTENT_SETTING_DEFAULT
;
500 // TODO(bauerb): Return rules as a list of values, not content settings.
501 // Handle the case using compound values for its exceptions and arbitrary
502 // values for its default setting. Here we assume all the exceptions
503 // are granted as |CONTENT_SETTING_ALLOW|.
504 if (ContentTypeHasCompoundValue(content_type
) &&
506 rule
.primary_pattern
!= ContentSettingsPattern::Wildcard()) {
507 setting_value
= CONTENT_SETTING_ALLOW
;
509 setting_value
= content_settings::ValueToContentSetting(rule
.value
.get());
511 settings
->push_back(ContentSettingPatternSource(
512 rule
.primary_pattern
, rule
.secondary_pattern
,
514 kProviderNames
[provider_type
],
519 void HostContentSettingsMap::UsedContentSettingsProviders() const {
521 if (used_from_thread_id_
== base::kInvalidThreadId
)
524 if (base::PlatformThread::CurrentId() != used_from_thread_id_
)
525 used_from_thread_id_
= base::kInvalidThreadId
;
529 bool HostContentSettingsMap::ShouldAllowAllContent(
530 const GURL
& primary_url
,
531 const GURL
& secondary_url
,
532 ContentSettingsType content_type
) {
533 if (content_type
== CONTENT_SETTINGS_TYPE_NOTIFICATIONS
||
534 content_type
== CONTENT_SETTINGS_TYPE_GEOLOCATION
||
535 content_type
== CONTENT_SETTINGS_TYPE_MIDI_SYSEX
) {
538 if (secondary_url
.SchemeIs(chrome::kChromeUIScheme
) &&
539 content_type
== CONTENT_SETTINGS_TYPE_COOKIES
&&
540 primary_url
.SchemeIsSecure()) {
543 if (primary_url
.SchemeIs(extensions::kExtensionScheme
)) {
544 switch (content_type
) {
545 case CONTENT_SETTINGS_TYPE_PLUGINS
:
546 case CONTENT_SETTINGS_TYPE_MEDIASTREAM
:
547 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
:
548 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
:
550 case CONTENT_SETTINGS_TYPE_COOKIES
:
551 return secondary_url
.SchemeIs(extensions::kExtensionScheme
);
556 return primary_url
.SchemeIs(chrome::kChromeDevToolsScheme
) ||
557 primary_url
.SchemeIs(chrome::kChromeUIScheme
);
560 base::Value
* HostContentSettingsMap::GetWebsiteSetting(
561 const GURL
& primary_url
,
562 const GURL
& secondary_url
,
563 ContentSettingsType content_type
,
564 const std::string
& resource_identifier
,
565 content_settings::SettingInfo
* info
) const {
566 DCHECK(SupportsResourceIdentifier(content_type
) ||
567 resource_identifier
.empty());
569 // Check if the scheme of the requesting url is whitelisted.
570 if (ShouldAllowAllContent(primary_url
, secondary_url
, content_type
)) {
572 info
->source
= content_settings::SETTING_SOURCE_WHITELIST
;
573 info
->primary_pattern
= ContentSettingsPattern::Wildcard();
574 info
->secondary_pattern
= ContentSettingsPattern::Wildcard();
576 return base::Value::CreateIntegerValue(CONTENT_SETTING_ALLOW
);
579 ContentSettingsPattern
* primary_pattern
= NULL
;
580 ContentSettingsPattern
* secondary_pattern
= NULL
;
582 primary_pattern
= &info
->primary_pattern
;
583 secondary_pattern
= &info
->secondary_pattern
;
586 // The list of |content_settings_providers_| is ordered according to their
588 for (ConstProviderIterator provider
= content_settings_providers_
.begin();
589 provider
!= content_settings_providers_
.end();
591 base::Value
* value
= content_settings::GetContentSettingValueAndPatterns(
592 provider
->second
, primary_url
, secondary_url
, content_type
,
593 resource_identifier
, is_off_the_record_
,
594 primary_pattern
, secondary_pattern
);
597 info
->source
= kProviderSourceMap
[provider
->first
];
603 info
->source
= content_settings::SETTING_SOURCE_NONE
;
604 info
->primary_pattern
= ContentSettingsPattern();
605 info
->secondary_pattern
= ContentSettingsPattern();
611 HostContentSettingsMap::ProviderType
612 HostContentSettingsMap::GetProviderTypeFromSource(
613 const std::string
& source
) {
614 for (size_t i
= 0; i
< arraysize(kProviderNames
); ++i
) {
615 if (source
== kProviderNames
[i
])
616 return static_cast<ProviderType
>(i
);
620 return DEFAULT_PROVIDER
;