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 void URLPatternSet::CreateDifference(const URLPatternSet
& set1
,
29 const URLPatternSet
& set2
,
31 out
->patterns_
= base::STLSetDifference
<std::set
<URLPattern
> >(
32 set1
.patterns_
, set2
.patterns_
);
36 void URLPatternSet::CreateIntersection(const URLPatternSet
& set1
,
37 const URLPatternSet
& set2
,
39 out
->patterns_
= base::STLSetIntersection
<std::set
<URLPattern
> >(
40 set1
.patterns_
, set2
.patterns_
);
44 void URLPatternSet::CreateUnion(const URLPatternSet
& set1
,
45 const URLPatternSet
& set2
,
47 out
->patterns_
= base::STLSetUnion
<std::set
<URLPattern
> >(
48 set1
.patterns_
, set2
.patterns_
);
52 void URLPatternSet::CreateUnion(const std::vector
<URLPatternSet
>& sets
,
58 // N-way union algorithm is basic O(nlog(n)) merge algorithm.
60 // Do the first merge step into a working set so that we don't mutate any of
62 std::vector
<URLPatternSet
> working
;
63 for (size_t i
= 0; i
< sets
.size(); i
+= 2) {
64 if (i
+ 1 < sets
.size()) {
66 URLPatternSet::CreateUnion(sets
[i
], sets
[i
+ 1], &u
);
69 working
.push_back(sets
[i
]);
73 for (size_t skip
= 1; skip
< working
.size(); skip
*= 2) {
74 for (size_t i
= 0; i
< (working
.size() - skip
); i
+= skip
) {
76 URLPatternSet::CreateUnion(working
[i
], working
[i
+ skip
], &u
);
77 working
[i
].patterns_
.swap(u
.patterns_
);
81 out
->patterns_
.swap(working
[0].patterns_
);
84 URLPatternSet::URLPatternSet() {}
86 URLPatternSet::URLPatternSet(const URLPatternSet
& rhs
)
87 : patterns_(rhs
.patterns_
) {}
89 URLPatternSet::URLPatternSet(const std::set
<URLPattern
>& patterns
)
90 : patterns_(patterns
) {}
92 URLPatternSet::~URLPatternSet() {}
94 URLPatternSet
& URLPatternSet::operator=(const URLPatternSet
& rhs
) {
95 patterns_
= rhs
.patterns_
;
99 bool URLPatternSet::operator==(const URLPatternSet
& other
) const {
100 return patterns_
== other
.patterns_
;
103 std::ostream
& operator<<(std::ostream
& out
,
104 const URLPatternSet
& url_pattern_set
) {
107 std::set
<URLPattern
>::const_iterator iter
=
108 url_pattern_set
.patterns().begin();
109 if (!url_pattern_set
.patterns().empty()) {
114 for (;iter
!= url_pattern_set
.patterns().end(); ++iter
)
115 out
<< ", " << *iter
;
117 if (!url_pattern_set
.patterns().empty())
124 bool URLPatternSet::is_empty() const {
125 return patterns_
.empty();
128 size_t URLPatternSet::size() const {
129 return patterns_
.size();
132 bool URLPatternSet::AddPattern(const URLPattern
& pattern
) {
133 return patterns_
.insert(pattern
).second
;
136 void URLPatternSet::AddPatterns(const URLPatternSet
& set
) {
137 patterns_
.insert(set
.patterns().begin(),
138 set
.patterns().end());
141 void URLPatternSet::ClearPatterns() {
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
) {
153 origin_pattern
.SetPath("/*");
154 return AddPattern(origin_pattern
);
157 bool URLPatternSet::Contains(const URLPatternSet
& other
) const {
158 for (URLPatternSet::const_iterator it
= other
.begin();
159 it
!= other
.end(); ++it
) {
160 if (!ContainsPattern(*it
))
167 bool URLPatternSet::ContainsPattern(const URLPattern
& pattern
) const {
168 for (URLPatternSet::const_iterator it
= begin();
170 if (it
->Contains(pattern
))
176 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
))
186 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()))
195 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
))
205 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
))
220 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()));
228 bool URLPatternSet::Populate(const std::vector
<std::string
>& patterns
,
230 bool allow_file_access
,
231 std::string
* error
) {
233 for (size_t i
= 0; i
< patterns
.size(); ++i
) {
234 URLPattern
pattern(valid_schemes
);
235 if (pattern
.Parse(patterns
[i
]) != URLPattern::PARSE_SUCCESS
) {
237 *error
= ErrorUtils::FormatErrorMessage(kInvalidURLPatternError
,
240 LOG(ERROR
) << "Invalid url pattern: " << patterns
[i
];
244 if (!allow_file_access
&& pattern
.MatchesScheme(url::kFileScheme
)) {
245 pattern
.SetValidSchemes(
246 pattern
.valid_schemes() & ~URLPattern::SCHEME_FILE
);
253 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();
258 value
->push_back(i
->GetAsString());
260 std::unique(value
->begin(), value
->end());
264 bool URLPatternSet::Populate(const base::ListValue
& value
,
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
) {
271 if (!value
.GetString(i
, &item
))
273 patterns
.push_back(item
);
275 return Populate(patterns
, valid_schemes
, allow_file_access
, error
);
278 } // namespace extensions