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.
5 #include "extensions/common/url_pattern_set.h"
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"
17 #include "url/url_constants.h"
19 namespace extensions
{
23 const char kInvalidURLPatternError
[] = "Invalid url pattern '*'";
28 URLPatternSet
URLPatternSet::CreateDifference(const URLPatternSet
& set1
,
29 const URLPatternSet
& set2
) {
30 return URLPatternSet(base::STLSetDifference
<std::set
<URLPattern
>>(
31 set1
.patterns_
, set2
.patterns_
));
35 URLPatternSet
URLPatternSet::CreateIntersection(const URLPatternSet
& set1
,
36 const URLPatternSet
& set2
) {
37 return URLPatternSet(base::STLSetIntersection
<std::set
<URLPattern
>>(
38 set1
.patterns_
, set2
.patterns_
));
41 URLPatternSet
URLPatternSet::CreateSemanticIntersection(
42 const URLPatternSet
& set1
,
43 const URLPatternSet
& set2
) {
45 for (const URLPattern
& pattern
: set1
) {
46 if (set2
.ContainsPattern(pattern
))
47 result
.patterns_
.insert(pattern
);
49 for (const URLPattern
& pattern
: set2
) {
50 if (set1
.ContainsPattern(pattern
))
51 result
.patterns_
.insert(pattern
);
57 URLPatternSet
URLPatternSet::CreateUnion(const URLPatternSet
& set1
,
58 const URLPatternSet
& set2
) {
60 base::STLSetUnion
<std::set
<URLPattern
>>(set1
.patterns_
, set2
.patterns_
));
64 URLPatternSet
URLPatternSet::CreateUnion(
65 const std::vector
<URLPatternSet
>& sets
) {
70 // N-way union algorithm is basic O(nlog(n)) merge algorithm.
72 // Do the first merge step into a working set so that we don't mutate any of
74 std::vector
<URLPatternSet
> working
;
75 for (size_t i
= 0; i
< sets
.size(); i
+= 2) {
76 if (i
+ 1 < sets
.size())
77 working
.push_back(CreateUnion(sets
[i
], sets
[i
+ 1]));
79 working
.push_back(sets
[i
]);
82 for (size_t skip
= 1; skip
< working
.size(); skip
*= 2) {
83 for (size_t i
= 0; i
< (working
.size() - skip
); i
+= skip
) {
84 URLPatternSet u
= CreateUnion(working
[i
], working
[i
+ skip
]);
85 working
[i
].patterns_
.swap(u
.patterns_
);
89 result
.patterns_
.swap(working
[0].patterns_
);
93 URLPatternSet::URLPatternSet() {}
95 URLPatternSet::URLPatternSet(const URLPatternSet
& rhs
)
96 : patterns_(rhs
.patterns_
) {}
98 URLPatternSet::URLPatternSet(const std::set
<URLPattern
>& patterns
)
99 : patterns_(patterns
) {}
101 URLPatternSet::~URLPatternSet() {}
103 URLPatternSet
& URLPatternSet::operator=(const URLPatternSet
& rhs
) {
104 patterns_
= rhs
.patterns_
;
108 bool URLPatternSet::operator==(const URLPatternSet
& other
) const {
109 return patterns_
== other
.patterns_
;
112 std::ostream
& operator<<(std::ostream
& out
,
113 const URLPatternSet
& url_pattern_set
) {
116 std::set
<URLPattern
>::const_iterator iter
=
117 url_pattern_set
.patterns().begin();
118 if (!url_pattern_set
.patterns().empty()) {
123 for (;iter
!= url_pattern_set
.patterns().end(); ++iter
)
124 out
<< ", " << *iter
;
126 if (!url_pattern_set
.patterns().empty())
133 bool URLPatternSet::is_empty() const {
134 return patterns_
.empty();
137 size_t URLPatternSet::size() const {
138 return patterns_
.size();
141 bool URLPatternSet::AddPattern(const URLPattern
& pattern
) {
142 return patterns_
.insert(pattern
).second
;
145 void URLPatternSet::AddPatterns(const URLPatternSet
& set
) {
146 patterns_
.insert(set
.patterns().begin(),
147 set
.patterns().end());
150 void URLPatternSet::ClearPatterns() {
154 bool URLPatternSet::AddOrigin(int valid_schemes
, const GURL
& origin
) {
155 DCHECK_EQ(origin
.GetOrigin(), origin
);
156 URLPattern
origin_pattern(valid_schemes
);
157 // Origin adding could fail if |origin| does not match |valid_schemes|.
158 if (origin_pattern
.Parse(origin
.GetOrigin().spec()) !=
159 URLPattern::PARSE_SUCCESS
) {
162 origin_pattern
.SetPath("/*");
163 return AddPattern(origin_pattern
);
166 bool URLPatternSet::Contains(const URLPatternSet
& other
) const {
167 for (URLPatternSet::const_iterator it
= other
.begin();
168 it
!= other
.end(); ++it
) {
169 if (!ContainsPattern(*it
))
176 bool URLPatternSet::ContainsPattern(const URLPattern
& pattern
) const {
177 for (URLPatternSet::const_iterator it
= begin();
179 if (it
->Contains(pattern
))
185 bool URLPatternSet::MatchesURL(const GURL
& url
) const {
186 for (URLPatternSet::const_iterator pattern
= patterns_
.begin();
187 pattern
!= patterns_
.end(); ++pattern
) {
188 if (pattern
->MatchesURL(url
))
195 bool URLPatternSet::MatchesAllURLs() const {
196 for (URLPatternSet::const_iterator host
= begin(); host
!= end(); ++host
) {
197 if (host
->match_all_urls() ||
198 (host
->match_subdomains() && host
->host().empty()))
204 bool URLPatternSet::MatchesSecurityOrigin(const GURL
& origin
) const {
205 for (URLPatternSet::const_iterator pattern
= patterns_
.begin();
206 pattern
!= patterns_
.end(); ++pattern
) {
207 if (pattern
->MatchesSecurityOrigin(origin
))
214 bool URLPatternSet::OverlapsWith(const URLPatternSet
& other
) const {
215 // Two extension extents overlap if there is any one URL that would match at
216 // least one pattern in each of the extents.
217 for (URLPatternSet::const_iterator i
= patterns_
.begin();
218 i
!= patterns_
.end(); ++i
) {
219 for (URLPatternSet::const_iterator j
= other
.patterns().begin();
220 j
!= other
.patterns().end(); ++j
) {
221 if (i
->OverlapsWith(*j
))
229 scoped_ptr
<base::ListValue
> URLPatternSet::ToValue() const {
230 scoped_ptr
<base::ListValue
> value(new base::ListValue
);
231 for (URLPatternSet::const_iterator i
= patterns_
.begin();
232 i
!= patterns_
.end(); ++i
)
233 value
->AppendIfNotPresent(new base::StringValue(i
->GetAsString()));
237 bool URLPatternSet::Populate(const std::vector
<std::string
>& patterns
,
239 bool allow_file_access
,
240 std::string
* error
) {
242 for (size_t i
= 0; i
< patterns
.size(); ++i
) {
243 URLPattern
pattern(valid_schemes
);
244 if (pattern
.Parse(patterns
[i
]) != URLPattern::PARSE_SUCCESS
) {
246 *error
= ErrorUtils::FormatErrorMessage(kInvalidURLPatternError
,
249 LOG(ERROR
) << "Invalid url pattern: " << patterns
[i
];
253 if (!allow_file_access
&& pattern
.MatchesScheme(url::kFileScheme
)) {
254 pattern
.SetValidSchemes(
255 pattern
.valid_schemes() & ~URLPattern::SCHEME_FILE
);
262 scoped_ptr
<std::vector
<std::string
> > URLPatternSet::ToStringVector() const {
263 scoped_ptr
<std::vector
<std::string
> > value(new std::vector
<std::string
>);
264 for (URLPatternSet::const_iterator i
= patterns_
.begin();
265 i
!= patterns_
.end();
267 value
->push_back(i
->GetAsString());
269 std::unique(value
->begin(), value
->end());
273 bool URLPatternSet::Populate(const base::ListValue
& value
,
275 bool allow_file_access
,
276 std::string
* error
) {
277 std::vector
<std::string
> patterns
;
278 for (size_t i
= 0; i
< value
.GetSize(); ++i
) {
280 if (!value
.GetString(i
, &item
))
282 patterns
.push_back(item
);
284 return Populate(patterns
, valid_schemes
, allow_file_access
, error
);
287 } // namespace extensions