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