Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(126)

Side by Side Diff: components/content_settings/core/browser/content_settings_pref.cc

Issue 976243002: Split content settings pref related logic into a separate class (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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.
4
5 #include "components/content_settings/core/browser/content_settings_pref.h"
6
7 #include "base/auto_reset.h"
8 #include "base/bind.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/scoped_user_pref_update.h"
12 #include "base/strings/string_split.h"
13 #include "base/time/clock.h"
14 #include "components/content_settings/core/browser/content_settings_rule.h"
15 #include "components/content_settings/core/browser/content_settings_utils.h"
16 #include "components/content_settings/core/browser/host_content_settings_map.h"
17 #include "components/content_settings/core/common/content_settings.h"
18 #include "components/content_settings/core/common/content_settings_pattern.h"
19 #include "components/content_settings/core/common/pref_names.h"
20 #include "url/gurl.h"
21
22 namespace {
23
24 typedef std::pair<std::string, std::string> StringPair;
25
26 const char kPerPluginPrefName[] = "per_plugin";
27 const char kLastUsed[] = "last_used";
28
29 ContentSetting FixObsoleteCookiePromptMode(ContentSettingsType content_type,
30 ContentSetting setting) {
31 if (content_type == CONTENT_SETTINGS_TYPE_COOKIES &&
32 setting == CONTENT_SETTING_ASK) {
33 return CONTENT_SETTING_BLOCK;
34 }
35 return setting;
36 }
37
38 // If the given content type supports resource identifiers in user preferences,
39 // returns true and sets |pref_key| to the key in the content settings
40 // dictionary under which per-resource content settings are stored.
41 // Otherwise, returns false.
42 bool GetResourceTypeName(ContentSettingsType content_type,
43 std::string* pref_key) {
44 if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
45 *pref_key = kPerPluginPrefName;
46 return true;
47 }
48 return false;
49 }
50
51 } // namespace
52
53 namespace content_settings {
54
55 ContentSettingsPref::ContentSettingsPref(
56 PrefService* prefs,
57 PrefChangeRegistrar* registrar,
58 base::Clock* clock,
59 bool incognito,
60 NotifyObserversCallback notify_callback)
61 : prefs_(prefs),
62 clock_(clock),
63 registrar_(registrar),
64 is_incognito_(incognito),
65 updating_preferences_(false),
66 notify_callback_(notify_callback) {
67 DCHECK(prefs_);
68
69 // Read content settings exceptions.
70 ReadContentSettingsFromPref();
71
72 registrar->Add(
73 prefs::kContentSettingsPatternPairs,
74 base::Bind(&ContentSettingsPref::OnContentSettingsPatternPairsChanged,
75 base::Unretained(this)));
76 }
77
78 ContentSettingsPref::~ContentSettingsPref() {
79 }
80
81 RuleIterator* ContentSettingsPref::GetRuleIterator(
82 ContentSettingsType content_type,
83 const ResourceIdentifier& resource_identifier,
84 bool incognito) const {
85 if (incognito)
86 return incognito_value_map_.GetRuleIterator(content_type,
87 resource_identifier,
88 &lock_);
89 return value_map_.GetRuleIterator(content_type, resource_identifier, &lock_);
90 }
91
92 bool ContentSettingsPref::SetWebsiteSetting(
93 const ContentSettingsPattern& primary_pattern,
94 const ContentSettingsPattern& secondary_pattern,
95 ContentSettingsType content_type,
96 const ResourceIdentifier& resource_identifier,
97 base::Value* in_value) {
98 DCHECK(thread_checker_.CalledOnValidThread());
99 DCHECK(prefs_);
100
101 // Default settings are set using a wildcard pattern for both
102 // |primary_pattern| and |secondary_pattern|. Don't store default settings in
103 // the |PrefProvider|. The |PrefProvider| handles settings for specific
104 // sites/origins defined by the |primary_pattern| and the |secondary_pattern|.
105 // Default settings are handled by the |DefaultProvider|.
106 if (primary_pattern == ContentSettingsPattern::Wildcard() &&
107 secondary_pattern == ContentSettingsPattern::Wildcard() &&
108 resource_identifier.empty()) {
109 return false;
110 }
111
112 // At this point take the ownership of the |in_value|.
113 scoped_ptr<base::Value> value(in_value);
114 // Update in memory value map.
115 OriginIdentifierValueMap* map_to_modify = &incognito_value_map_;
116 if (!is_incognito_)
117 map_to_modify = &value_map_;
118
119 {
120 base::AutoLock auto_lock(lock_);
121 if (value.get()) {
122 map_to_modify->SetValue(
123 primary_pattern,
124 secondary_pattern,
125 content_type,
126 resource_identifier,
127 value->DeepCopy());
128 } else {
129 map_to_modify->DeleteValue(
130 primary_pattern,
131 secondary_pattern,
132 content_type,
133 resource_identifier);
134 }
135 }
136 // Update the content settings preference.
137 if (!is_incognito_) {
138 UpdatePref(primary_pattern,
139 secondary_pattern,
140 content_type,
141 resource_identifier,
142 value.get());
143 }
144
145 notify_callback_.Run(
146 primary_pattern, secondary_pattern, content_type, resource_identifier);
147
148 return true;
149 }
150
151 void ContentSettingsPref::ClearAllContentSettingsRules(
152 ContentSettingsType content_type) {
153 DCHECK(thread_checker_.CalledOnValidThread());
154 DCHECK(prefs_);
155
156 OriginIdentifierValueMap* map_to_modify = &incognito_value_map_;
157 if (!is_incognito_)
158 map_to_modify = &value_map_;
159
160 std::vector<Rule> rules_to_delete;
161 {
162 base::AutoLock auto_lock(lock_);
163 scoped_ptr<RuleIterator> rule_iterator(
164 map_to_modify->GetRuleIterator(content_type, std::string(), NULL));
165 // Copy the rules; we cannot call |UpdatePref| while holding |lock_|.
166 while (rule_iterator->HasNext())
167 rules_to_delete.push_back(rule_iterator->Next());
168
169 map_to_modify->DeleteValues(content_type, std::string());
170 }
171
172 for (std::vector<Rule>::const_iterator it = rules_to_delete.begin();
173 it != rules_to_delete.end(); ++it) {
174 UpdatePref(it->primary_pattern,
175 it->secondary_pattern,
176 content_type,
177 std::string(),
178 NULL);
179 }
180 notify_callback_.Run(ContentSettingsPattern(),
181 ContentSettingsPattern(),
182 content_type,
183 std::string());
184 }
185
186 void ContentSettingsPref::UpdateLastUsage(
187 const ContentSettingsPattern& primary_pattern,
188 const ContentSettingsPattern& secondary_pattern,
189 ContentSettingsType content_type) {
190 // Don't write if in incognito.
191 if (is_incognito_) {
192 return;
193 }
194
195 // Ensure that |lock_| is not held by this thread, since this function will
196 // send out notifications (by |~DictionaryPrefUpdate|).
197 AssertLockNotHeld();
198
199 base::AutoReset<bool> auto_reset(&updating_preferences_, true);
200 {
201 DictionaryPrefUpdate update(prefs_, prefs::kContentSettingsPatternPairs);
202 base::DictionaryValue* pattern_pairs_settings = update.Get();
203
204 std::string pattern_str(
205 CreatePatternString(primary_pattern, secondary_pattern));
206 base::DictionaryValue* settings_dictionary = NULL;
207 bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion(
208 pattern_str, &settings_dictionary);
209
210 if (!found) {
211 settings_dictionary = new base::DictionaryValue;
212 pattern_pairs_settings->SetWithoutPathExpansion(pattern_str,
213 settings_dictionary);
214 }
215
216 base::DictionaryValue* last_used_dictionary = NULL;
217 found = settings_dictionary->GetDictionaryWithoutPathExpansion(
218 kLastUsed, &last_used_dictionary);
219
220 if (!found) {
221 last_used_dictionary = new base::DictionaryValue;
222 settings_dictionary->SetWithoutPathExpansion(kLastUsed,
223 last_used_dictionary);
224 }
225
226 std::string settings_path = GetTypeName(content_type);
227 last_used_dictionary->Set(
228 settings_path, new base::FundamentalValue(clock_->Now().ToDoubleT()));
229 }
230 }
231
232 base::Time ContentSettingsPref::GetLastUsage(
233 const ContentSettingsPattern& primary_pattern,
234 const ContentSettingsPattern& secondary_pattern,
235 ContentSettingsType content_type) {
236 const base::DictionaryValue* pattern_pairs_settings =
237 prefs_->GetDictionary(prefs::kContentSettingsPatternPairs);
238 std::string pattern_str(
239 CreatePatternString(primary_pattern, secondary_pattern));
240
241 const base::DictionaryValue* settings_dictionary = NULL;
242 bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion(
243 pattern_str, &settings_dictionary);
244
245 if (!found)
246 return base::Time();
247
248 const base::DictionaryValue* last_used_dictionary = NULL;
249 found = settings_dictionary->GetDictionaryWithoutPathExpansion(
250 kLastUsed, &last_used_dictionary);
251
252 if (!found)
253 return base::Time();
254
255 double last_used_time;
256 found = last_used_dictionary->GetDoubleWithoutPathExpansion(
257 GetTypeName(content_type), &last_used_time);
258
259 if (!found)
260 return base::Time();
261
262 return base::Time::FromDoubleT(last_used_time);
263 }
264
265 size_t ContentSettingsPref::GetNumExceptions() {
266 return value_map_.size();
267 }
268
269 void ContentSettingsPref::SetClockForTesting(base::Clock* clock) {
270 clock_ = clock;
271 }
272
273 void ContentSettingsPref::ReadContentSettingsFromPref() {
274 // |DictionaryPrefUpdate| sends out notifications when destructed. This
275 // construction order ensures |AutoLock| gets destroyed first and |lock_| is
276 // not held when the notifications are sent. Also, |auto_reset| must be still
277 // valid when the notifications are sent, so that |Observe| skips the
278 // notification.
279 base::AutoReset<bool> auto_reset(&updating_preferences_, true);
280 DictionaryPrefUpdate update(prefs_, prefs::kContentSettingsPatternPairs);
281 base::AutoLock auto_lock(lock_);
282
283 const base::DictionaryValue* all_settings_dictionary =
284 prefs_->GetDictionary(prefs::kContentSettingsPatternPairs);
285
286 value_map_.clear();
287
288 // Careful: The returned value could be NULL if the pref has never been set.
289 if (!all_settings_dictionary)
290 return;
291
292 base::DictionaryValue* mutable_settings;
293 scoped_ptr<base::DictionaryValue> mutable_settings_scope;
294
295 if (!is_incognito_) {
296 mutable_settings = update.Get();
297 } else {
298 // Create copy as we do not want to persist anything in OTR prefs.
299 mutable_settings = all_settings_dictionary->DeepCopy();
300 mutable_settings_scope.reset(mutable_settings);
301 }
302 // Convert all Unicode patterns into punycode form, then read.
303 CanonicalizeContentSettingsExceptions(mutable_settings);
304
305 size_t cookies_block_exception_count = 0;
306 size_t cookies_allow_exception_count = 0;
307 size_t cookies_session_only_exception_count = 0;
308 for (base::DictionaryValue::Iterator i(*mutable_settings); !i.IsAtEnd();
309 i.Advance()) {
310 const std::string& pattern_str(i.key());
311 std::pair<ContentSettingsPattern, ContentSettingsPattern> pattern_pair =
312 ParsePatternString(pattern_str);
313 if (!pattern_pair.first.IsValid() ||
314 !pattern_pair.second.IsValid()) {
315 // TODO: Change this to DFATAL when crbug.com/132659 is fixed.
316 LOG(ERROR) << "Invalid pattern strings: " << pattern_str;
317 continue;
318 }
319
320 // Get settings dictionary for the current pattern string, and read
321 // settings from the dictionary.
322 const base::DictionaryValue* settings_dictionary = NULL;
323 bool is_dictionary = i.value().GetAsDictionary(&settings_dictionary);
324 DCHECK(is_dictionary);
325
326 for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
327 ContentSettingsType content_type = static_cast<ContentSettingsType>(i);
328
329 std::string res_dictionary_path;
330 if (GetResourceTypeName(content_type, &res_dictionary_path)) {
331 const base::DictionaryValue* resource_dictionary = NULL;
332 if (settings_dictionary->GetDictionary(
333 res_dictionary_path, &resource_dictionary)) {
334 for (base::DictionaryValue::Iterator j(*resource_dictionary);
335 !j.IsAtEnd();
336 j.Advance()) {
337 const std::string& resource_identifier(j.key());
338 int setting = CONTENT_SETTING_DEFAULT;
339 bool is_integer = j.value().GetAsInteger(&setting);
340 DCHECK(is_integer);
341 DCHECK_NE(CONTENT_SETTING_DEFAULT, setting);
342 value_map_.SetValue(pattern_pair.first,
343 pattern_pair.second,
344 content_type,
345 resource_identifier,
346 new base::FundamentalValue(setting));
347 }
348 }
349 }
350 base::Value* value = NULL;
351 if (HostContentSettingsMap::ContentTypeHasCompoundValue(content_type)) {
352 const base::DictionaryValue* setting = NULL;
353 // TODO(xians): Handle the non-dictionary types.
354 if (settings_dictionary->GetDictionaryWithoutPathExpansion(
355 GetTypeName(ContentSettingsType(i)), &setting)) {
356 DCHECK(!setting->empty());
357 value = setting->DeepCopy();
358 }
359 } else {
360 int setting = CONTENT_SETTING_DEFAULT;
361 if (settings_dictionary->GetIntegerWithoutPathExpansion(
362 GetTypeName(ContentSettingsType(i)), &setting)) {
363 DCHECK_NE(CONTENT_SETTING_DEFAULT, setting);
364 setting = FixObsoleteCookiePromptMode(content_type,
365 ContentSetting(setting));
366 value = new base::FundamentalValue(setting);
367 }
368 }
369
370 // |value_map_| will take the ownership of |value|.
371 if (value != NULL) {
372 value_map_.SetValue(pattern_pair.first,
373 pattern_pair.second,
374 content_type,
375 ResourceIdentifier(),
376 value);
377 if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
378 ContentSetting s = ValueToContentSetting(value);
379 switch (s) {
380 case CONTENT_SETTING_ALLOW :
381 ++cookies_allow_exception_count;
382 break;
383 case CONTENT_SETTING_BLOCK :
384 ++cookies_block_exception_count;
385 break;
386 case CONTENT_SETTING_SESSION_ONLY :
387 ++cookies_session_only_exception_count;
388 break;
389 default:
390 NOTREACHED();
391 break;
392 }
393 }
394 }
395 }
396 }
397 UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfBlockCookiesExceptions",
398 cookies_block_exception_count);
399 UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfAllowCookiesExceptions",
400 cookies_allow_exception_count);
401 UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfSessionOnlyCookiesExceptions",
402 cookies_session_only_exception_count);
403 }
404
405 void ContentSettingsPref::OnContentSettingsPatternPairsChanged() {
406 DCHECK(thread_checker_.CalledOnValidThread());
407
408 if (updating_preferences_)
409 return;
410
411 ReadContentSettingsFromPref();
412
413 notify_callback_.Run(ContentSettingsPattern(),
414 ContentSettingsPattern(),
415 CONTENT_SETTINGS_TYPE_DEFAULT,
416 std::string());
417 }
418
419 void ContentSettingsPref::UpdatePref(
420 const ContentSettingsPattern& primary_pattern,
421 const ContentSettingsPattern& secondary_pattern,
422 ContentSettingsType content_type,
423 const ResourceIdentifier& resource_identifier,
424 const base::Value* value) {
425 // Ensure that |lock_| is not held by this thread, since this function will
426 // send out notifications (by |~DictionaryPrefUpdate|).
427 AssertLockNotHeld();
428
429 base::AutoReset<bool> auto_reset(&updating_preferences_, true);
430 {
431 DictionaryPrefUpdate update(prefs_,
432 prefs::kContentSettingsPatternPairs);
433 base::DictionaryValue* pattern_pairs_settings = update.Get();
434
435 // Get settings dictionary for the given patterns.
436 std::string pattern_str(CreatePatternString(primary_pattern,
437 secondary_pattern));
438 base::DictionaryValue* settings_dictionary = NULL;
439 bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion(
440 pattern_str, &settings_dictionary);
441
442 if (!found && value) {
443 settings_dictionary = new base::DictionaryValue;
444 pattern_pairs_settings->SetWithoutPathExpansion(
445 pattern_str, settings_dictionary);
446 }
447
448 if (settings_dictionary) {
449 std::string res_dictionary_path;
450 if (GetResourceTypeName(content_type, &res_dictionary_path) &&
451 !resource_identifier.empty()) {
452 base::DictionaryValue* resource_dictionary = NULL;
453 found = settings_dictionary->GetDictionary(
454 res_dictionary_path, &resource_dictionary);
455 if (!found) {
456 if (value == NULL)
457 return; // Nothing to remove. Exit early.
458 resource_dictionary = new base::DictionaryValue;
459 settings_dictionary->Set(res_dictionary_path, resource_dictionary);
460 }
461 // Update resource dictionary.
462 if (value == NULL) {
463 resource_dictionary->RemoveWithoutPathExpansion(resource_identifier,
464 NULL);
465 if (resource_dictionary->empty()) {
466 settings_dictionary->RemoveWithoutPathExpansion(
467 res_dictionary_path, NULL);
468 }
469 } else {
470 resource_dictionary->SetWithoutPathExpansion(
471 resource_identifier, value->DeepCopy());
472 }
473 } else {
474 // Update settings dictionary.
475 std::string setting_path = GetTypeName(content_type);
476 if (value == NULL) {
477 settings_dictionary->RemoveWithoutPathExpansion(setting_path,
478 NULL);
479 settings_dictionary->RemoveWithoutPathExpansion(kLastUsed, NULL);
480 } else {
481 settings_dictionary->SetWithoutPathExpansion(
482 setting_path, value->DeepCopy());
483 }
484 }
485 // Remove the settings dictionary if it is empty.
486 if (settings_dictionary->empty()) {
487 pattern_pairs_settings->RemoveWithoutPathExpansion(
488 pattern_str, NULL);
489 }
490 }
491 }
492 }
493
494 // static
495 void ContentSettingsPref::CanonicalizeContentSettingsExceptions(
496 base::DictionaryValue* all_settings_dictionary) {
497 DCHECK(all_settings_dictionary);
498
499 std::vector<std::string> remove_items;
500 base::StringPairs move_items;
501 for (base::DictionaryValue::Iterator i(*all_settings_dictionary);
502 !i.IsAtEnd();
503 i.Advance()) {
504 const std::string& pattern_str(i.key());
505 std::pair<ContentSettingsPattern, ContentSettingsPattern> pattern_pair =
506 ParsePatternString(pattern_str);
507 if (!pattern_pair.first.IsValid() ||
508 !pattern_pair.second.IsValid()) {
509 LOG(ERROR) << "Invalid pattern strings: " << pattern_str;
510 continue;
511 }
512
513 const std::string canonicalized_pattern_str = CreatePatternString(
514 pattern_pair.first, pattern_pair.second);
515
516 if (canonicalized_pattern_str.empty() ||
517 canonicalized_pattern_str == pattern_str) {
518 continue;
519 }
520
521 // Clear old pattern if prefs already have canonicalized pattern.
522 const base::DictionaryValue* new_pattern_settings_dictionary = NULL;
523 if (all_settings_dictionary->GetDictionaryWithoutPathExpansion(
524 canonicalized_pattern_str, &new_pattern_settings_dictionary)) {
525 remove_items.push_back(pattern_str);
526 continue;
527 }
528
529 // Move old pattern to canonicalized pattern.
530 const base::DictionaryValue* old_pattern_settings_dictionary = NULL;
531 if (i.value().GetAsDictionary(&old_pattern_settings_dictionary)) {
532 move_items.push_back(
533 std::make_pair(pattern_str, canonicalized_pattern_str));
534 }
535 }
536
537 for (size_t i = 0; i < remove_items.size(); ++i) {
538 all_settings_dictionary->RemoveWithoutPathExpansion(remove_items[i], NULL);
539 }
540
541 for (size_t i = 0; i < move_items.size(); ++i) {
542 scoped_ptr<base::Value> pattern_settings_dictionary;
543 all_settings_dictionary->RemoveWithoutPathExpansion(
544 move_items[i].first, &pattern_settings_dictionary);
545 all_settings_dictionary->SetWithoutPathExpansion(
546 move_items[i].second, pattern_settings_dictionary.release());
547 }
548 }
549
550 void ContentSettingsPref::AssertLockNotHeld() const {
551 #if !defined(NDEBUG)
552 // |Lock::Acquire()| will assert if the lock is held by this thread.
553 lock_.Acquire();
554 lock_.Release();
555 #endif
556 }
557
558 } // namespace content_settings
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698