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 "chrome/common/content_settings_pattern_parser.h"
7 #include "base/strings/string_util.h"
8 #include "chrome/common/url_constants.h"
9 #include "extensions/common/constants.h"
10 #include "net/base/net_util.h"
12 #include "url/url_canon.h"
16 const char* kUrlPathSeparator
= "/";
17 const char* kUrlPortSeparator
= ":";
21 Component() : start(0), len(0) {}
22 Component(size_t s
, size_t l
) : start(s
), len(l
) {}
34 namespace content_settings
{
36 const char* PatternParser::kDomainWildcard
= "[*.]";
38 const size_t PatternParser::kDomainWildcardLength
= 4;
40 const char* PatternParser::kSchemeWildcard
= "*";
42 const char* PatternParser::kHostWildcard
= "*";
44 const char* PatternParser::kPortWildcard
= "*";
46 const char* PatternParser::kPathWildcard
= "*";
49 void PatternParser::Parse(const std::string
& pattern_spec
,
50 ContentSettingsPattern::BuilderInterface
* builder
) {
51 if (pattern_spec
== "*") {
52 builder
->WithSchemeWildcard();
53 builder
->WithDomainWildcard();
54 builder
->WithPortWildcard();
58 // Initialize components for the individual patterns parts to empty
60 Component scheme_component
;
61 Component host_component
;
62 Component port_component
;
63 Component path_component
;
66 size_t current_pos
= 0;
68 if (pattern_spec
.empty())
71 // Test if a scheme pattern is in the spec.
72 current_pos
= pattern_spec
.find(
73 std::string(content::kStandardSchemeSeparator
), start
);
74 if (current_pos
!= std::string::npos
) {
75 scheme_component
= Component(start
, current_pos
);
76 start
= current_pos
+ strlen(content::kStandardSchemeSeparator
);
82 if (start
>= pattern_spec
.size())
83 return; // Bad pattern spec.
85 // Jump to the end of domain wildcards or an IPv6 addresses. IPv6 addresses
86 // contain ':'. So first move to the end of an IPv6 address befor searching
87 // for the ':' that separates the port form the host.
88 if (pattern_spec
[current_pos
] == '[')
89 current_pos
= pattern_spec
.find("]", start
);
91 if (current_pos
== std::string::npos
)
92 return; // Bad pattern spec.
94 current_pos
= pattern_spec
.find(std::string(kUrlPortSeparator
), current_pos
);
95 if (current_pos
== std::string::npos
) {
97 current_pos
= pattern_spec
.find(std::string(kUrlPathSeparator
), start
);
98 if (current_pos
== std::string::npos
) {
99 current_pos
= pattern_spec
.size();
100 host_component
= Component(start
, current_pos
- start
);
102 // Pattern has a path spec.
103 host_component
= Component(start
, current_pos
- start
);
108 host_component
= Component(start
, current_pos
- start
);
109 start
= current_pos
+ 1;
110 if (start
< pattern_spec
.size()) {
111 current_pos
= pattern_spec
.find(std::string(kUrlPathSeparator
), start
);
112 if (current_pos
== std::string::npos
) {
113 current_pos
= pattern_spec
.size();
115 port_component
= Component(start
, current_pos
- start
);
120 current_pos
= pattern_spec
.size();
121 if (start
< current_pos
) {
122 // Pattern has a path spec.
123 path_component
= Component(start
, current_pos
- start
);
126 // Set pattern parts.
128 if (scheme_component
.IsNonEmpty()) {
129 scheme
= pattern_spec
.substr(scheme_component
.start
, scheme_component
.len
);
130 if (scheme
== kSchemeWildcard
) {
131 builder
->WithSchemeWildcard();
133 builder
->WithScheme(scheme
);
136 builder
->WithSchemeWildcard();
139 if (host_component
.IsNonEmpty()) {
140 std::string host
= pattern_spec
.substr(host_component
.start
,
142 if (host
== kHostWildcard
) {
143 builder
->WithDomainWildcard();
144 } else if (StartsWithASCII(host
, kDomainWildcard
, true)) {
145 host
= host
.substr(kDomainWildcardLength
);
146 builder
->WithDomainWildcard();
147 builder
->WithHost(host
);
149 // If the host contains a wildcard symbol then it is invalid.
150 if (host
.find(kHostWildcard
) != std::string::npos
) {
154 builder
->WithHost(host
);
158 if (port_component
.IsNonEmpty()) {
159 const std::string port
= pattern_spec
.substr(port_component
.start
,
161 if (port
== kPortWildcard
) {
162 builder
->WithPortWildcard();
164 // Check if the port string represents a valid port.
165 for (size_t i
= 0; i
< port
.size(); ++i
) {
166 if (!IsAsciiDigit(port
[i
])) {
171 // TODO(markusheintz): Check port range.
172 builder
->WithPort(port
);
175 if (scheme
!= std::string(extensions::kExtensionScheme
) &&
176 scheme
!= std::string(content::kFileScheme
))
177 builder
->WithPortWildcard();
180 if (path_component
.IsNonEmpty()) {
181 const std::string path
= pattern_spec
.substr(path_component
.start
,
183 if (path
.substr(1) == kPathWildcard
)
184 builder
->WithPathWildcard();
186 builder
->WithPath(path
);
191 std::string
PatternParser::ToString(
192 const ContentSettingsPattern::PatternParts
& parts
) {
193 // Return the most compact form to support legacy code and legacy pattern
195 if (parts
.is_scheme_wildcard
&&
196 parts
.has_domain_wildcard
&&
197 parts
.host
.empty() &&
198 parts
.is_port_wildcard
)
202 if (!parts
.is_scheme_wildcard
)
203 str
+= parts
.scheme
+ content::kStandardSchemeSeparator
;
205 if (parts
.scheme
== content::kFileScheme
) {
206 if (parts
.is_path_wildcard
)
207 return str
+ kUrlPathSeparator
+ kPathWildcard
;
209 return str
+ parts
.path
;
212 if (parts
.has_domain_wildcard
) {
213 if (parts
.host
.empty())
214 str
+= kHostWildcard
;
216 str
+= kDomainWildcard
;
220 if (parts
.scheme
== std::string(extensions::kExtensionScheme
)) {
221 str
+= parts
.path
.empty() ? std::string(kUrlPathSeparator
) : parts
.path
;
225 if (!parts
.is_port_wildcard
) {
226 str
+= std::string(kUrlPortSeparator
) + parts
.port
;
232 } // namespace content_settings