Suppress tabs permission warning if there is already a browsingHistory warning.
[chromium-blink-merge.git] / chrome / common / content_settings_pattern_parser.cc
blobc8c22ed9a3fc18bb1950e51a0b503269426c7f97
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"
11 #include "url/gurl.h"
12 #include "url/url_canon.h"
14 namespace {
16 const char* kUrlPathSeparator = "/";
17 const char* kUrlPortSeparator = ":";
19 class Component {
20 public:
21 Component() : start(0), len(0) {}
22 Component(size_t s, size_t l) : start(s), len(l) {}
24 bool IsNonEmpty() {
25 return len > 0;
28 size_t start;
29 size_t len;
32 } // namespace
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 = "*";
48 // static
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();
55 return;
58 // Initialize components for the individual patterns parts to empty
59 // sub-strings.
60 Component scheme_component;
61 Component host_component;
62 Component port_component;
63 Component path_component;
65 size_t start = 0;
66 size_t current_pos = 0;
68 if (pattern_spec.empty())
69 return;
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);
77 current_pos = start;
78 } else {
79 current_pos = start;
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) {
96 // No port spec found
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);
101 } else {
102 // Pattern has a path spec.
103 host_component = Component(start, current_pos - start);
105 start = current_pos;
106 } else {
107 // Port spec found.
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);
116 start = current_pos;
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.
127 std::string scheme;
128 if (scheme_component.IsNonEmpty()) {
129 scheme = pattern_spec.substr(scheme_component.start, scheme_component.len);
130 if (scheme == kSchemeWildcard) {
131 builder->WithSchemeWildcard();
132 } else {
133 builder->WithScheme(scheme);
135 } else {
136 builder->WithSchemeWildcard();
139 if (host_component.IsNonEmpty()) {
140 std::string host = pattern_spec.substr(host_component.start,
141 host_component.len);
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);
148 } else {
149 // If the host contains a wildcard symbol then it is invalid.
150 if (host.find(kHostWildcard) != std::string::npos) {
151 builder->Invalid();
152 return;
154 builder->WithHost(host);
158 if (port_component.IsNonEmpty()) {
159 const std::string port = pattern_spec.substr(port_component.start,
160 port_component.len);
161 if (port == kPortWildcard) {
162 builder->WithPortWildcard();
163 } else {
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])) {
167 builder->Invalid();
168 return;
171 // TODO(markusheintz): Check port range.
172 builder->WithPort(port);
174 } else {
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,
182 path_component.len);
183 if (path.substr(1) == kPathWildcard)
184 builder->WithPathWildcard();
185 else
186 builder->WithPath(path);
190 // static
191 std::string PatternParser::ToString(
192 const ContentSettingsPattern::PatternParts& parts) {
193 // Return the most compact form to support legacy code and legacy pattern
194 // strings.
195 if (parts.is_scheme_wildcard &&
196 parts.has_domain_wildcard &&
197 parts.host.empty() &&
198 parts.is_port_wildcard)
199 return "*";
201 std::string str;
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;
208 else
209 return str + parts.path;
212 if (parts.has_domain_wildcard) {
213 if (parts.host.empty())
214 str += kHostWildcard;
215 else
216 str += kDomainWildcard;
218 str += parts.host;
220 if (parts.scheme == std::string(extensions::kExtensionScheme)) {
221 str += parts.path.empty() ? std::string(kUrlPathSeparator) : parts.path;
222 return str;
225 if (!parts.is_port_wildcard) {
226 str += std::string(kUrlPortSeparator) + parts.port;
229 return str;
232 } // namespace content_settings