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