| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/content_settings/content_settings_origin_identifier_value_map.h" |
| |
| #include "base/compiler_specific.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/synchronization/lock.h" |
| #include "base/values.h" |
| #include "chrome/browser/content_settings/content_settings_rule.h" |
| #include "chrome/browser/content_settings/content_settings_utils.h" |
| #include "chrome/common/content_settings_types.h" |
| #include "url/gurl.h" |
| |
| namespace content_settings { |
| |
| namespace { |
| |
| // This iterator is used for iterating the rules for |content_type| and |
| // |resource_identifier| in the precedence order of the rules. |
| class RuleIteratorImpl : public RuleIterator { |
| public: |
| // |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) |
| : current_rule_(current_rule), |
| rule_end_(rule_end), |
| auto_lock_(auto_lock) { |
| } |
| virtual ~RuleIteratorImpl() {} |
| |
| virtual bool HasNext() const OVERRIDE { |
| return (current_rule_ != rule_end_); |
| } |
| |
| virtual Rule Next() OVERRIDE { |
| DCHECK(current_rule_ != rule_end_); |
| DCHECK(current_rule_->second.get()); |
| Rule to_return(current_rule_->first.primary_pattern, |
| current_rule_->first.secondary_pattern, |
| current_rule_->second.get()->DeepCopy()); |
| ++current_rule_; |
| return to_return; |
| } |
| |
| private: |
| OriginIdentifierValueMap::Rules::const_iterator current_rule_; |
| OriginIdentifierValueMap::Rules::const_iterator rule_end_; |
| scoped_ptr<base::AutoLock> auto_lock_; |
| }; |
| |
| } // namespace |
| |
| OriginIdentifierValueMap::EntryMapKey::EntryMapKey( |
| ContentSettingsType content_type, |
| const ResourceIdentifier& resource_identifier) |
| : content_type(content_type), |
| resource_identifier(resource_identifier) { |
| } |
| |
| bool OriginIdentifierValueMap::EntryMapKey::operator<( |
| const OriginIdentifierValueMap::EntryMapKey& other) const { |
| if (content_type != other.content_type) |
| return content_type < other.content_type; |
| return (resource_identifier < other.resource_identifier); |
| } |
| |
| OriginIdentifierValueMap::PatternPair::PatternPair( |
| const ContentSettingsPattern& primary_pattern, |
| const ContentSettingsPattern& secondary_pattern) |
| : primary_pattern(primary_pattern), |
| secondary_pattern(secondary_pattern) { |
| } |
| |
| bool OriginIdentifierValueMap::PatternPair::operator<( |
| const OriginIdentifierValueMap::PatternPair& other) const { |
| // Note that this operator is the other way around than |
| // |ContentSettingsPattern::operator<|. It sorts patterns with higher |
| // precedence first. |
| if (primary_pattern > other.primary_pattern) |
| return true; |
| else if (other.primary_pattern > primary_pattern) |
| return false; |
| return (secondary_pattern > other.secondary_pattern); |
| } |
| |
| RuleIterator* OriginIdentifierValueMap::GetRuleIterator( |
| ContentSettingsType content_type, |
| const ResourceIdentifier& resource_identifier, |
| base::Lock* lock) const { |
| EntryMapKey key(content_type, resource_identifier); |
| // We access |entries_| here, so we need to lock |lock_| first. The lock must |
| // be passed to the |RuleIteratorImpl| in a locked state, so that nobody can |
| // access |entries_| after |find()| but before the |RuleIteratorImpl| is |
| // created. |
| scoped_ptr<base::AutoLock> auto_lock; |
| if (lock) |
| auto_lock.reset(new base::AutoLock(*lock)); |
| EntryMap::const_iterator it = entries_.find(key); |
| if (it == entries_.end()) |
| return new EmptyRuleIterator(); |
| return new RuleIteratorImpl(it->second.begin(), |
| it->second.end(), |
| auto_lock.release()); |
| } |
| |
| size_t OriginIdentifierValueMap::size() const { |
| size_t size = 0; |
| EntryMap::const_iterator it; |
| for (it = entries_.begin(); it != entries_.end(); ++it) |
| size += it->second.size(); |
| return size; |
| } |
| |
| OriginIdentifierValueMap::OriginIdentifierValueMap() {} |
| |
| OriginIdentifierValueMap::~OriginIdentifierValueMap() {} |
| |
| base::Value* OriginIdentifierValueMap::GetValue( |
| const GURL& primary_url, |
| const GURL& secondary_url, |
| ContentSettingsType content_type, |
| const ResourceIdentifier& resource_identifier) const { |
| EntryMapKey key(content_type, resource_identifier); |
| EntryMap::const_iterator it = entries_.find(key); |
| if (it == entries_.end()) |
| return NULL; |
| |
| // Iterate the entries in until a match is found. Since the rules are stored |
| // in the order of decreasing precedence, the most specific match is found |
| // first. |
| Rules::const_iterator entry; |
| for (entry = it->second.begin(); entry != it->second.end(); ++entry) { |
| if (entry->first.primary_pattern.Matches(primary_url) && |
| entry->first.secondary_pattern.Matches(secondary_url)) { |
| return entry->second.get(); |
| } |
| } |
| return NULL; |
| } |
| |
| void OriginIdentifierValueMap::SetValue( |
| const ContentSettingsPattern& primary_pattern, |
| const ContentSettingsPattern& secondary_pattern, |
| ContentSettingsType content_type, |
| const ResourceIdentifier& resource_identifier, |
| base::Value* value) { |
| DCHECK(primary_pattern.IsValid()); |
| DCHECK(secondary_pattern.IsValid()); |
| DCHECK(value); |
| EntryMapKey key(content_type, resource_identifier); |
| PatternPair patterns(primary_pattern, secondary_pattern); |
| // This will create the entry and the linked_ptr if needed. |
| entries_[key][patterns].reset(value); |
| } |
| |
| void OriginIdentifierValueMap::DeleteValue( |
| const ContentSettingsPattern& primary_pattern, |
| const ContentSettingsPattern& secondary_pattern, |
| ContentSettingsType content_type, |
| const ResourceIdentifier& resource_identifier) { |
| EntryMapKey key(content_type, resource_identifier); |
| PatternPair patterns(primary_pattern, secondary_pattern); |
| entries_[key].erase(patterns); |
| if (entries_[key].empty()) { |
| entries_.erase(key); |
| } |
| } |
| |
| void OriginIdentifierValueMap::DeleteValues( |
| ContentSettingsType content_type, |
| const ResourceIdentifier& resource_identifier) { |
| EntryMapKey key(content_type, resource_identifier); |
| entries_.erase(key); |
| } |
| |
| void OriginIdentifierValueMap::clear() { |
| // Delete all owned value objects. |
| entries_.clear(); |
| } |
| |
| } // namespace content_settings |