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.
4
5 #include "components/content_settings/core/browser/content_settings_origin_identifier_value_map.h"
6
7 #include <memory>
8 #include <tuple>
9
10 #include "base/compiler_specific.h"
11 #include "base/logging.h"
12 #include "base/synchronization/lock.h"
13 #include "base/values.h"
14 #include "components/content_settings/core/browser/content_settings_rule.h"
15 #include "components/content_settings/core/common/content_settings_types.h"
16 #include "url/gurl.h"
17
18 namespace content_settings {
19
20 namespace {
21
22 // This iterator is used for iterating the rules for |content_type| and
23 // |resource_identifier| in the precedence order of the rules.
24 class RuleIteratorImpl : public RuleIterator {
25 public:
26 // |RuleIteratorImpl| takes the ownership of |auto_lock|.
RuleIteratorImpl(const OriginIdentifierValueMap::Rules::const_iterator & current_rule,const OriginIdentifierValueMap::Rules::const_iterator & rule_end,base::AutoLock * auto_lock)27 RuleIteratorImpl(
28 const OriginIdentifierValueMap::Rules::const_iterator& current_rule,
29 const OriginIdentifierValueMap::Rules::const_iterator& rule_end,
30 base::AutoLock* auto_lock)
31 : current_rule_(current_rule),
32 rule_end_(rule_end),
33 auto_lock_(auto_lock) {
34 }
~RuleIteratorImpl()35 ~RuleIteratorImpl() override {}
36
HasNext() const37 bool HasNext() const override { return (current_rule_ != rule_end_); }
38
Next()39 Rule Next() override {
40 DCHECK(HasNext());
41 Rule to_return(current_rule_->first.primary_pattern,
42 current_rule_->first.secondary_pattern,
43 current_rule_->second.value.Clone());
44 ++current_rule_;
45 return to_return;
46 }
47
48 private:
49 OriginIdentifierValueMap::Rules::const_iterator current_rule_;
50 OriginIdentifierValueMap::Rules::const_iterator rule_end_;
51 std::unique_ptr<base::AutoLock> auto_lock_;
52 };
53
54 } // namespace
55
EntryMapKey(ContentSettingsType content_type,const ResourceIdentifier & resource_identifier)56 OriginIdentifierValueMap::EntryMapKey::EntryMapKey(
57 ContentSettingsType content_type,
58 const ResourceIdentifier& resource_identifier)
59 : content_type(content_type),
60 resource_identifier(resource_identifier) {
61 }
62
operator <(const OriginIdentifierValueMap::EntryMapKey & other) const63 bool OriginIdentifierValueMap::EntryMapKey::operator<(
64 const OriginIdentifierValueMap::EntryMapKey& other) const {
65 return std::tie(content_type, resource_identifier) <
66 std::tie(other.content_type, other.resource_identifier);
67 }
68
PatternPair(const ContentSettingsPattern & primary_pattern,const ContentSettingsPattern & secondary_pattern)69 OriginIdentifierValueMap::PatternPair::PatternPair(
70 const ContentSettingsPattern& primary_pattern,
71 const ContentSettingsPattern& secondary_pattern)
72 : primary_pattern(primary_pattern),
73 secondary_pattern(secondary_pattern) {
74 }
75
operator <(const OriginIdentifierValueMap::PatternPair & other) const76 bool OriginIdentifierValueMap::PatternPair::operator<(
77 const OriginIdentifierValueMap::PatternPair& other) const {
78 // Note that this operator is the other way around than
79 // |ContentSettingsPattern::operator<|. It sorts patterns with higher
80 // precedence first.
81 return std::tie(primary_pattern, secondary_pattern) >
82 std::tie(other.primary_pattern, other.secondary_pattern);
83 }
84
ValueEntry()85 OriginIdentifierValueMap::ValueEntry::ValueEntry() {}
86
~ValueEntry()87 OriginIdentifierValueMap::ValueEntry::~ValueEntry() {}
88
GetRuleIterator(ContentSettingsType content_type,const ResourceIdentifier & resource_identifier,base::Lock * lock) const89 std::unique_ptr<RuleIterator> OriginIdentifierValueMap::GetRuleIterator(
90 ContentSettingsType content_type,
91 const ResourceIdentifier& resource_identifier,
92 base::Lock* lock) const {
93 EntryMapKey key(content_type, resource_identifier);
94 // We access |entries_| here, so we need to lock |lock_| first. The lock must
95 // be passed to the |RuleIteratorImpl| in a locked state, so that nobody can
96 // access |entries_| after |find()| but before the |RuleIteratorImpl| is
97 // created.
98 std::unique_ptr<base::AutoLock> auto_lock;
99 if (lock)
100 auto_lock.reset(new base::AutoLock(*lock));
101 auto it = entries_.find(key);
102 if (it == entries_.end())
103 return nullptr;
104 return std::unique_ptr<RuleIterator>(new RuleIteratorImpl(
105 it->second.begin(), it->second.end(), auto_lock.release()));
106 }
107
size() const108 size_t OriginIdentifierValueMap::size() const {
109 size_t size = 0;
110 for (const auto& entry : entries_)
111 size += entry.second.size();
112 return size;
113 }
114
OriginIdentifierValueMap()115 OriginIdentifierValueMap::OriginIdentifierValueMap() {}
116
~OriginIdentifierValueMap()117 OriginIdentifierValueMap::~OriginIdentifierValueMap() {}
118
GetValue(const GURL & primary_url,const GURL & secondary_url,ContentSettingsType content_type,const ResourceIdentifier & resource_identifier) const119 const base::Value* OriginIdentifierValueMap::GetValue(
120 const GURL& primary_url,
121 const GURL& secondary_url,
122 ContentSettingsType content_type,
123 const ResourceIdentifier& resource_identifier) const {
124 EntryMapKey key(content_type, resource_identifier);
125 auto it = entries_.find(key);
126 if (it == entries_.end())
127 return nullptr;
128
129 // Iterate the entries in until a match is found. Since the rules are stored
130 // in the order of decreasing precedence, the most specific match is found
131 // first.
132 for (const auto& entry : it->second) {
133 if (entry.first.primary_pattern.Matches(primary_url) &&
134 entry.first.secondary_pattern.Matches(secondary_url)) {
135 return &entry.second.value;
136 }
137 }
138 return nullptr;
139 }
140
GetLastModified(const ContentSettingsPattern & primary_pattern,const ContentSettingsPattern & secondary_pattern,ContentSettingsType content_type,const ResourceIdentifier & resource_identifier) const141 base::Time OriginIdentifierValueMap::GetLastModified(
142 const ContentSettingsPattern& primary_pattern,
143 const ContentSettingsPattern& secondary_pattern,
144 ContentSettingsType content_type,
145 const ResourceIdentifier& resource_identifier) const {
146 DCHECK(primary_pattern.IsValid());
147 DCHECK(secondary_pattern.IsValid());
148
149 EntryMapKey key(content_type, resource_identifier);
150 PatternPair patterns(primary_pattern, secondary_pattern);
151 auto it = entries_.find(key);
152 if (it == entries_.end())
153 return base::Time();
154 auto r = it->second.find(patterns);
155 if (r == it->second.end())
156 return base::Time();
157 return r->second.last_modified;
158 }
159
SetValue(const ContentSettingsPattern & primary_pattern,const ContentSettingsPattern & secondary_pattern,ContentSettingsType content_type,const ResourceIdentifier & resource_identifier,base::Time last_modified,base::Value value)160 void OriginIdentifierValueMap::SetValue(
161 const ContentSettingsPattern& primary_pattern,
162 const ContentSettingsPattern& secondary_pattern,
163 ContentSettingsType content_type,
164 const ResourceIdentifier& resource_identifier,
165 base::Time last_modified,
166 base::Value value) {
167 DCHECK(primary_pattern.IsValid());
168 DCHECK(secondary_pattern.IsValid());
169 // TODO(raymes): Remove this after we track down the cause of
170 // crbug.com/531548.
171 CHECK_NE(ContentSettingsType::DEFAULT, content_type);
172 EntryMapKey key(content_type, resource_identifier);
173 PatternPair patterns(primary_pattern, secondary_pattern);
174 ValueEntry* entry = &entries_[key][patterns];
175 entry->value = std::move(value);
176 entry->last_modified = last_modified;
177 }
178
DeleteValue(const ContentSettingsPattern & primary_pattern,const ContentSettingsPattern & secondary_pattern,ContentSettingsType content_type,const ResourceIdentifier & resource_identifier)179 void OriginIdentifierValueMap::DeleteValue(
180 const ContentSettingsPattern& primary_pattern,
181 const ContentSettingsPattern& secondary_pattern,
182 ContentSettingsType content_type,
183 const ResourceIdentifier& resource_identifier) {
184 EntryMapKey key(content_type, resource_identifier);
185 PatternPair patterns(primary_pattern, secondary_pattern);
186 auto it = entries_.find(key);
187 if (it == entries_.end())
188 return;
189 it->second.erase(patterns);
190 if (it->second.empty())
191 entries_.erase(it);
192 }
193
DeleteValues(ContentSettingsType content_type,const ResourceIdentifier & resource_identifier)194 void OriginIdentifierValueMap::DeleteValues(
195 ContentSettingsType content_type,
196 const ResourceIdentifier& resource_identifier) {
197 EntryMapKey key(content_type, resource_identifier);
198 entries_.erase(key);
199 }
200
clear()201 void OriginIdentifierValueMap::clear() {
202 // Delete all owned value objects.
203 entries_.clear();
204 }
205
206 } // namespace content_settings
207