2
* Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* 2. Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
13
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
#include "UserContentURLPattern.h"
30
#include <wtf/StdLibExtras.h>
34
bool UserContentURLPattern::matchesPatterns(const KURL& url, const Vector<String>& whitelist, const Vector<String>& blacklist)
36
// In order for a URL to be a match it has to be present in the whitelist and not present in the blacklist.
37
// If there is no whitelist at all, then all URLs are assumed to be in the whitelist.
38
bool matchesWhitelist = whitelist.isEmpty();
39
if (!matchesWhitelist) {
40
size_t whitelistSize = whitelist.size();
41
for (size_t i = 0; i < whitelistSize; ++i) {
42
UserContentURLPattern contentPattern(whitelist[i]);
43
if (contentPattern.matches(url)) {
44
matchesWhitelist = true;
50
bool matchesBlacklist = false;
51
if (!blacklist.isEmpty()) {
52
size_t blacklistSize = blacklist.size();
53
for (size_t i = 0; i < blacklistSize; ++i) {
54
UserContentURLPattern contentPattern(blacklist[i]);
55
if (contentPattern.matches(url)) {
56
matchesBlacklist = true;
62
return matchesWhitelist && !matchesBlacklist;
65
bool UserContentURLPattern::parse(const String& pattern)
67
DEFINE_STATIC_LOCAL(const String, schemeSeparator, (ASCIILiteral("://")));
69
size_t schemeEndPos = pattern.find(schemeSeparator);
70
if (schemeEndPos == notFound)
73
m_scheme = pattern.left(schemeEndPos);
75
unsigned hostStartPos = schemeEndPos + schemeSeparator.length();
76
if (hostStartPos >= pattern.length())
81
if (equalIgnoringCase(m_scheme, "file"))
82
pathStartPos = hostStartPos;
84
size_t hostEndPos = pattern.find("/", hostStartPos);
85
if (hostEndPos == notFound)
88
m_host = pattern.substring(hostStartPos, hostEndPos - hostStartPos);
89
m_matchSubdomains = false;
92
// The pattern can be just '*', which means match all domains.
94
m_matchSubdomains = true;
95
} else if (m_host.startsWith("*.")) {
96
// The first component can be '*', which means to match all subdomains.
97
m_host = m_host.substring(2); // Length of "*."
98
m_matchSubdomains = true;
101
// No other '*' can occur in the host.
102
if (m_host.find("*") != notFound)
105
pathStartPos = hostEndPos;
108
m_path = pattern.right(pattern.length() - pathStartPos);
113
bool UserContentURLPattern::matches(const KURL& test) const
118
if (!equalIgnoringCase(test.protocol(), m_scheme))
121
if (!equalIgnoringCase(m_scheme, "file") && !matchesHost(test))
124
return matchesPath(test);
127
bool UserContentURLPattern::matchesHost(const KURL& test) const
129
const String& host = test.host();
130
if (equalIgnoringCase(host, m_host))
133
if (!m_matchSubdomains)
136
// If we're matching subdomains, and we have no host, that means the pattern
137
// was <scheme>://*/<whatever>, so we match anything.
138
if (!m_host.length())
141
// Check if the domain is a subdomain of our host.
142
if (!host.endsWith(m_host, false))
145
ASSERT(host.length() > m_host.length());
147
// Check that the character before the suffix is a period.
148
return host[host.length() - m_host.length() - 1] == '.';
153
const String m_pattern;
154
unsigned m_patternIndex;
157
unsigned m_testIndex;
159
MatchTester(const String& pattern, const String& test)
167
bool testStringFinished() const { return m_testIndex >= m_test.length(); }
168
bool patternStringFinished() const { return m_patternIndex >= m_pattern.length(); }
172
while (!patternStringFinished()) {
173
if (m_pattern[m_patternIndex] != '*')
181
while (!patternStringFinished() && !testStringFinished()) {
182
if (m_pattern[m_patternIndex] == '*')
184
if (m_pattern[m_patternIndex] != m_test[m_testIndex])
193
// Eat all the matching chars.
196
// If the string is finished, then the pattern must be empty too, or contains
198
if (testStringFinished()) {
200
if (patternStringFinished())
205
// Pattern is empty but not string, this is not a match.
206
if (patternStringFinished())
209
// If we don't encounter a *, then we're hosed.
210
if (m_pattern[m_patternIndex] != '*')
213
while (!testStringFinished()) {
214
MatchTester nextMatch(*this);
215
nextMatch.m_patternIndex++;
216
if (nextMatch.test())
221
// We reached the end of the string. Let's see if the pattern contains only
224
return patternStringFinished();
228
bool UserContentURLPattern::matchesPath(const KURL& test) const
230
MatchTester match(m_path, test.path());
234
} // namespace WebCore