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