• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <iterator>
8 #include <ostream>
9 
10 #include "base/logging.h"
11 #include "base/memory/linked_ptr.h"
12 #include "base/stl_util.h"
13 #include "base/values.h"
14 #include "extensions/common/error_utils.h"
15 #include "extensions/common/url_pattern.h"
16 #include "url/gurl.h"
17 #include "url/url_constants.h"
18 
19 namespace extensions {
20 
21 namespace {
22 
23 const char kInvalidURLPatternError[] = "Invalid url pattern '*'";
24 
25 }  // namespace
26 
27 // static
CreateDifference(const URLPatternSet & set1,const URLPatternSet & set2,URLPatternSet * out)28 void URLPatternSet::CreateDifference(const URLPatternSet& set1,
29                                      const URLPatternSet& set2,
30                                      URLPatternSet* out) {
31   out->patterns_ = base::STLSetDifference<std::set<URLPattern> >(
32       set1.patterns_, set2.patterns_);
33 }
34 
35 // static
CreateIntersection(const URLPatternSet & set1,const URLPatternSet & set2,URLPatternSet * out)36 void URLPatternSet::CreateIntersection(const URLPatternSet& set1,
37                                        const URLPatternSet& set2,
38                                        URLPatternSet* out) {
39   out->patterns_ = base::STLSetIntersection<std::set<URLPattern> >(
40       set1.patterns_, set2.patterns_);
41 }
42 
43 // static
CreateUnion(const URLPatternSet & set1,const URLPatternSet & set2,URLPatternSet * out)44 void URLPatternSet::CreateUnion(const URLPatternSet& set1,
45                                 const URLPatternSet& set2,
46                                 URLPatternSet* out) {
47   out->patterns_ = base::STLSetUnion<std::set<URLPattern> >(
48       set1.patterns_, set2.patterns_);
49 }
50 
51 // static
CreateUnion(const std::vector<URLPatternSet> & sets,URLPatternSet * out)52 void URLPatternSet::CreateUnion(const std::vector<URLPatternSet>& sets,
53                                 URLPatternSet* out) {
54   out->ClearPatterns();
55   if (sets.empty())
56     return;
57 
58   // N-way union algorithm is basic O(nlog(n)) merge algorithm.
59   //
60   // Do the first merge step into a working set so that we don't mutate any of
61   // the input.
62   std::vector<URLPatternSet> working;
63   for (size_t i = 0; i < sets.size(); i += 2) {
64     if (i + 1 < sets.size()) {
65       URLPatternSet u;
66       URLPatternSet::CreateUnion(sets[i], sets[i + 1], &u);
67       working.push_back(u);
68     } else {
69       working.push_back(sets[i]);
70     }
71   }
72 
73   for (size_t skip = 1; skip < working.size(); skip *= 2) {
74     for (size_t i = 0; i < (working.size() - skip); i += skip) {
75       URLPatternSet u;
76       URLPatternSet::CreateUnion(working[i], working[i + skip], &u);
77       working[i].patterns_.swap(u.patterns_);
78     }
79   }
80 
81   out->patterns_.swap(working[0].patterns_);
82 }
83 
URLPatternSet()84 URLPatternSet::URLPatternSet() {}
85 
URLPatternSet(const URLPatternSet & rhs)86 URLPatternSet::URLPatternSet(const URLPatternSet& rhs)
87     : patterns_(rhs.patterns_) {}
88 
URLPatternSet(const std::set<URLPattern> & patterns)89 URLPatternSet::URLPatternSet(const std::set<URLPattern>& patterns)
90     : patterns_(patterns) {}
91 
~URLPatternSet()92 URLPatternSet::~URLPatternSet() {}
93 
operator =(const URLPatternSet & rhs)94 URLPatternSet& URLPatternSet::operator=(const URLPatternSet& rhs) {
95   patterns_ = rhs.patterns_;
96   return *this;
97 }
98 
operator ==(const URLPatternSet & other) const99 bool URLPatternSet::operator==(const URLPatternSet& other) const {
100   return patterns_ == other.patterns_;
101 }
102 
operator <<(std::ostream & out,const URLPatternSet & url_pattern_set)103 std::ostream& operator<<(std::ostream& out,
104                          const URLPatternSet& url_pattern_set) {
105   out << "{ ";
106 
107   std::set<URLPattern>::const_iterator iter =
108       url_pattern_set.patterns().begin();
109   if (!url_pattern_set.patterns().empty()) {
110     out << *iter;
111     ++iter;
112   }
113 
114   for (;iter != url_pattern_set.patterns().end(); ++iter)
115     out << ", " << *iter;
116 
117   if (!url_pattern_set.patterns().empty())
118     out << " ";
119 
120   out << "}";
121   return out;
122 }
123 
is_empty() const124 bool URLPatternSet::is_empty() const {
125   return patterns_.empty();
126 }
127 
size() const128 size_t URLPatternSet::size() const {
129   return patterns_.size();
130 }
131 
AddPattern(const URLPattern & pattern)132 bool URLPatternSet::AddPattern(const URLPattern& pattern) {
133   return patterns_.insert(pattern).second;
134 }
135 
AddPatterns(const URLPatternSet & set)136 void URLPatternSet::AddPatterns(const URLPatternSet& set) {
137   patterns_.insert(set.patterns().begin(),
138                    set.patterns().end());
139 }
140 
ClearPatterns()141 void URLPatternSet::ClearPatterns() {
142   patterns_.clear();
143 }
144 
AddOrigin(int valid_schemes,const GURL & origin)145 bool URLPatternSet::AddOrigin(int valid_schemes, const GURL& origin) {
146   DCHECK_EQ(origin.GetOrigin(), origin);
147   URLPattern origin_pattern(valid_schemes);
148   // Origin adding could fail if |origin| does not match |valid_schemes|.
149   if (origin_pattern.Parse(origin.GetOrigin().spec()) !=
150       URLPattern::PARSE_SUCCESS) {
151     return false;
152   }
153   origin_pattern.SetPath("/*");
154   return AddPattern(origin_pattern);
155 }
156 
Contains(const URLPatternSet & other) const157 bool URLPatternSet::Contains(const URLPatternSet& other) const {
158   for (URLPatternSet::const_iterator it = other.begin();
159        it != other.end(); ++it) {
160     if (!ContainsPattern(*it))
161       return false;
162   }
163 
164   return true;
165 }
166 
ContainsPattern(const URLPattern & pattern) const167 bool URLPatternSet::ContainsPattern(const URLPattern& pattern) const {
168   for (URLPatternSet::const_iterator it = begin();
169        it != end(); ++it) {
170     if (it->Contains(pattern))
171       return true;
172   }
173   return false;
174 }
175 
MatchesURL(const GURL & url) const176 bool URLPatternSet::MatchesURL(const GURL& url) const {
177   for (URLPatternSet::const_iterator pattern = patterns_.begin();
178        pattern != patterns_.end(); ++pattern) {
179     if (pattern->MatchesURL(url))
180       return true;
181   }
182 
183   return false;
184 }
185 
MatchesAllURLs() const186 bool URLPatternSet::MatchesAllURLs() const {
187   for (URLPatternSet::const_iterator host = begin(); host != end(); ++host) {
188     if (host->match_all_urls() ||
189         (host->match_subdomains() && host->host().empty()))
190       return true;
191   }
192   return false;
193 }
194 
MatchesSecurityOrigin(const GURL & origin) const195 bool URLPatternSet::MatchesSecurityOrigin(const GURL& origin) const {
196   for (URLPatternSet::const_iterator pattern = patterns_.begin();
197        pattern != patterns_.end(); ++pattern) {
198     if (pattern->MatchesSecurityOrigin(origin))
199       return true;
200   }
201 
202   return false;
203 }
204 
OverlapsWith(const URLPatternSet & other) const205 bool URLPatternSet::OverlapsWith(const URLPatternSet& other) const {
206   // Two extension extents overlap if there is any one URL that would match at
207   // least one pattern in each of the extents.
208   for (URLPatternSet::const_iterator i = patterns_.begin();
209        i != patterns_.end(); ++i) {
210     for (URLPatternSet::const_iterator j = other.patterns().begin();
211          j != other.patterns().end(); ++j) {
212       if (i->OverlapsWith(*j))
213         return true;
214     }
215   }
216 
217   return false;
218 }
219 
ToValue() const220 scoped_ptr<base::ListValue> URLPatternSet::ToValue() const {
221   scoped_ptr<base::ListValue> value(new base::ListValue);
222   for (URLPatternSet::const_iterator i = patterns_.begin();
223        i != patterns_.end(); ++i)
224     value->AppendIfNotPresent(new base::StringValue(i->GetAsString()));
225   return value.Pass();
226 }
227 
Populate(const std::vector<std::string> & patterns,int valid_schemes,bool allow_file_access,std::string * error)228 bool URLPatternSet::Populate(const std::vector<std::string>& patterns,
229                              int valid_schemes,
230                              bool allow_file_access,
231                              std::string* error) {
232   ClearPatterns();
233   for (size_t i = 0; i < patterns.size(); ++i) {
234     URLPattern pattern(valid_schemes);
235     if (pattern.Parse(patterns[i]) != URLPattern::PARSE_SUCCESS) {
236       if (error) {
237         *error = ErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
238                                                 patterns[i]);
239       } else {
240         LOG(ERROR) << "Invalid url pattern: " << patterns[i];
241       }
242       return false;
243     }
244     if (!allow_file_access && pattern.MatchesScheme(url::kFileScheme)) {
245       pattern.SetValidSchemes(
246           pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
247     }
248     AddPattern(pattern);
249   }
250   return true;
251 }
252 
ToStringVector() const253 scoped_ptr<std::vector<std::string> > URLPatternSet::ToStringVector() const {
254   scoped_ptr<std::vector<std::string> > value(new std::vector<std::string>);
255   for (URLPatternSet::const_iterator i = patterns_.begin();
256        i != patterns_.end();
257        ++i) {
258     value->push_back(i->GetAsString());
259   }
260   std::unique(value->begin(), value->end());
261   return value.Pass();
262 }
263 
Populate(const base::ListValue & value,int valid_schemes,bool allow_file_access,std::string * error)264 bool URLPatternSet::Populate(const base::ListValue& value,
265                              int valid_schemes,
266                              bool allow_file_access,
267                              std::string* error) {
268   std::vector<std::string> patterns;
269   for (size_t i = 0; i < value.GetSize(); ++i) {
270     std::string item;
271     if (!value.GetString(i, &item))
272       return false;
273     patterns.push_back(item);
274   }
275   return Populate(patterns, valid_schemes, allow_file_access, error);
276 }
277 
278 }  // namespace extensions
279