Home | History | Annotate | Download | only in common
      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 "extensions/common/url_pattern_set.h"
      6 
      7 #include <algorithm>
      8 #include <iterator>
      9 
     10 #include "base/logging.h"
     11 #include "base/memory/linked_ptr.h"
     12 #include "base/values.h"
     13 #include "content/public/common/url_constants.h"
     14 #include "extensions/common/error_utils.h"
     15 #include "extensions/common/url_pattern.h"
     16 #include "url/gurl.h"
     17 
     18 namespace extensions {
     19 
     20 namespace {
     21 
     22 const char kInvalidURLPatternError[] = "Invalid url pattern '*'";
     23 
     24 }  // namespace
     25 
     26 // static
     27 void URLPatternSet::CreateDifference(const URLPatternSet& set1,
     28                                      const URLPatternSet& set2,
     29                                      URLPatternSet* out) {
     30   out->ClearPatterns();
     31   std::set_difference(set1.patterns_.begin(), set1.patterns_.end(),
     32                       set2.patterns_.begin(), set2.patterns_.end(),
     33                       std::inserter<std::set<URLPattern> >(
     34                           out->patterns_, out->patterns_.begin()));
     35 }
     36 
     37 // static
     38 void URLPatternSet::CreateIntersection(const URLPatternSet& set1,
     39                                        const URLPatternSet& set2,
     40                                        URLPatternSet* out) {
     41   out->ClearPatterns();
     42   std::set_intersection(set1.patterns_.begin(), set1.patterns_.end(),
     43                         set2.patterns_.begin(), set2.patterns_.end(),
     44                         std::inserter<std::set<URLPattern> >(
     45                             out->patterns_, out->patterns_.begin()));
     46 }
     47 
     48 // static
     49 void URLPatternSet::CreateUnion(const URLPatternSet& set1,
     50                                 const URLPatternSet& set2,
     51                                 URLPatternSet* out) {
     52   out->ClearPatterns();
     53   std::set_union(set1.patterns_.begin(), set1.patterns_.end(),
     54                  set2.patterns_.begin(), set2.patterns_.end(),
     55                  std::inserter<std::set<URLPattern> >(
     56                      out->patterns_, out->patterns_.begin()));
     57 }
     58 
     59 // static
     60 void URLPatternSet::CreateUnion(const std::vector<URLPatternSet>& sets,
     61                                 URLPatternSet* out) {
     62   out->ClearPatterns();
     63   if (sets.empty())
     64     return;
     65 
     66   // N-way union algorithm is basic O(nlog(n)) merge algorithm.
     67   //
     68   // Do the first merge step into a working set so that we don't mutate any of
     69   // the input.
     70   std::vector<URLPatternSet> working;
     71   for (size_t i = 0; i < sets.size(); i += 2) {
     72     if (i + 1 < sets.size()) {
     73       URLPatternSet u;
     74       URLPatternSet::CreateUnion(sets[i], sets[i + 1], &u);
     75       working.push_back(u);
     76     } else {
     77       working.push_back(sets[i]);
     78     }
     79   }
     80 
     81   for (size_t skip = 1; skip < working.size(); skip *= 2) {
     82     for (size_t i = 0; i < (working.size() - skip); i += skip) {
     83       URLPatternSet u;
     84       URLPatternSet::CreateUnion(working[i], working[i + skip], &u);
     85       working[i].patterns_.swap(u.patterns_);
     86     }
     87   }
     88 
     89   out->patterns_.swap(working[0].patterns_);
     90 }
     91 
     92 URLPatternSet::URLPatternSet() {}
     93 
     94 URLPatternSet::URLPatternSet(const URLPatternSet& rhs)
     95     : patterns_(rhs.patterns_) {}
     96 
     97 URLPatternSet::URLPatternSet(const std::set<URLPattern>& patterns)
     98     : patterns_(patterns) {}
     99 
    100 URLPatternSet::~URLPatternSet() {}
    101 
    102 URLPatternSet& URLPatternSet::operator=(const URLPatternSet& rhs) {
    103   patterns_ = rhs.patterns_;
    104   return *this;
    105 }
    106 
    107 bool URLPatternSet::operator==(const URLPatternSet& other) const {
    108   return patterns_ == other.patterns_;
    109 }
    110 
    111 bool URLPatternSet::is_empty() const {
    112   return patterns_.empty();
    113 }
    114 
    115 size_t URLPatternSet::size() const {
    116   return patterns_.size();
    117 }
    118 
    119 bool URLPatternSet::AddPattern(const URLPattern& pattern) {
    120   return patterns_.insert(pattern).second;
    121 }
    122 
    123 void URLPatternSet::AddPatterns(const URLPatternSet& set) {
    124   patterns_.insert(set.patterns().begin(),
    125                    set.patterns().end());
    126 }
    127 
    128 void URLPatternSet::ClearPatterns() {
    129   patterns_.clear();
    130 }
    131 
    132 bool URLPatternSet::Contains(const URLPatternSet& other) const {
    133   for (URLPatternSet::const_iterator it = other.begin();
    134        it != other.end(); ++it) {
    135     if (!ContainsPattern(*it))
    136       return false;
    137   }
    138 
    139   return true;
    140 }
    141 
    142 bool URLPatternSet::ContainsPattern(const URLPattern& pattern) const {
    143   for (URLPatternSet::const_iterator it = begin();
    144        it != end(); ++it) {
    145     if (it->Contains(pattern))
    146       return true;
    147   }
    148   return false;
    149 }
    150 
    151 bool URLPatternSet::MatchesURL(const GURL& url) const {
    152   for (URLPatternSet::const_iterator pattern = patterns_.begin();
    153        pattern != patterns_.end(); ++pattern) {
    154     if (pattern->MatchesURL(url))
    155       return true;
    156   }
    157 
    158   return false;
    159 }
    160 
    161 bool URLPatternSet::MatchesSecurityOrigin(const GURL& origin) const {
    162   for (URLPatternSet::const_iterator pattern = patterns_.begin();
    163        pattern != patterns_.end(); ++pattern) {
    164     if (pattern->MatchesSecurityOrigin(origin))
    165       return true;
    166   }
    167 
    168   return false;
    169 }
    170 
    171 bool URLPatternSet::OverlapsWith(const URLPatternSet& other) const {
    172   // Two extension extents overlap if there is any one URL that would match at
    173   // least one pattern in each of the extents.
    174   for (URLPatternSet::const_iterator i = patterns_.begin();
    175        i != patterns_.end(); ++i) {
    176     for (URLPatternSet::const_iterator j = other.patterns().begin();
    177          j != other.patterns().end(); ++j) {
    178       if (i->OverlapsWith(*j))
    179         return true;
    180     }
    181   }
    182 
    183   return false;
    184 }
    185 
    186 scoped_ptr<base::ListValue> URLPatternSet::ToValue() const {
    187   scoped_ptr<ListValue> value(new ListValue);
    188   for (URLPatternSet::const_iterator i = patterns_.begin();
    189        i != patterns_.end(); ++i)
    190     value->AppendIfNotPresent(Value::CreateStringValue(i->GetAsString()));
    191   return value.Pass();
    192 }
    193 
    194 bool URLPatternSet::Populate(const std::vector<std::string>& patterns,
    195                              int valid_schemes,
    196                              bool allow_file_access,
    197                              std::string* error) {
    198   ClearPatterns();
    199   for (size_t i = 0; i < patterns.size(); ++i) {
    200     URLPattern pattern(valid_schemes);
    201     if (pattern.Parse(patterns[i]) != URLPattern::PARSE_SUCCESS) {
    202       if (error) {
    203         *error = ErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
    204                                                 patterns[i]);
    205       } else {
    206         LOG(ERROR) << "Invalid url pattern: " << patterns[i];
    207       }
    208       return false;
    209     }
    210     if (!allow_file_access && pattern.MatchesScheme(chrome::kFileScheme)) {
    211       pattern.SetValidSchemes(
    212           pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
    213     }
    214     AddPattern(pattern);
    215   }
    216   return true;
    217 }
    218 
    219 bool URLPatternSet::Populate(const base::ListValue& value,
    220                              int valid_schemes,
    221                              bool allow_file_access,
    222                              std::string* error) {
    223   std::vector<std::string> patterns;
    224   for (size_t i = 0; i < value.GetSize(); ++i) {
    225     std::string item;
    226     if (!value.GetString(i, &item))
    227       return false;
    228     patterns.push_back(item);
    229   }
    230   return Populate(patterns, valid_schemes, allow_file_access, error);
    231 }
    232 
    233 }  // namespace extensions
    234