- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / common / content_settings_pattern_parser.cc
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.
4
5 #include "chrome/common/content_settings_pattern_parser.h"
6
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"
13
14 namespace {
15
16 const char* kUrlPathSeparator = "/";
17 const char* kUrlPortSeparator = ":";
18
19 class Component {
20  public:
21   Component() : start(0), len(0) {}
22   Component(size_t s, size_t l) : start(s), len(l) {}
23
24   bool IsNonEmpty() {
25     return len > 0;
26   }
27
28   size_t start;
29   size_t len;
30 };
31
32 }  // namespace
33
34 namespace content_settings {
35
36 const char* PatternParser::kDomainWildcard = "[*.]";
37
38 const size_t PatternParser::kDomainWildcardLength = 4;
39
40 const char* PatternParser::kSchemeWildcard = "*";
41
42 const char* PatternParser::kHostWildcard = "*";
43
44 const char* PatternParser::kPortWildcard = "*";
45
46 const char* PatternParser::kPathWildcard = "*";
47
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;
56   }
57
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;
64
65   size_t start = 0;
66   size_t current_pos = 0;
67
68   if (pattern_spec.empty())
69     return;
70
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;
80   }
81
82   if (start >= pattern_spec.size())
83     return;  // Bad pattern spec.
84
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);
90
91   if (current_pos == std::string::npos)
92     return;  // Bad pattern spec.
93
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);
104     }
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();
114       }
115       port_component = Component(start, current_pos - start);
116       start = current_pos;
117     }
118   }
119
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);
124   }
125
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);
134     }
135   } else {
136     builder->WithSchemeWildcard();
137   }
138
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;
153       }
154       builder->WithHost(host);
155     }
156   }
157
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;
169         }
170       }
171       // TODO(markusheintz): Check port range.
172       builder->WithPort(port);
173     }
174   } else {
175     if (scheme != std::string(extensions::kExtensionScheme) &&
176         scheme != std::string(chrome::kFileScheme))
177       builder->WithPortWildcard();
178   }
179
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);
187   }
188 }
189
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 "*";
200
201   std::string str;
202   if (!parts.is_scheme_wildcard)
203     str += parts.scheme + content::kStandardSchemeSeparator;
204
205   if (parts.scheme == chrome::kFileScheme) {
206     if (parts.is_path_wildcard)
207       return str + kUrlPathSeparator + kPathWildcard;
208     else
209       return str + parts.path;
210   }
211
212   if (parts.has_domain_wildcard) {
213     if (parts.host.empty())
214       str += kHostWildcard;
215     else
216       str += kDomainWildcard;
217   }
218   str += parts.host;
219
220   if (parts.scheme == std::string(extensions::kExtensionScheme)) {
221     str += parts.path.empty() ? std::string(kUrlPathSeparator) : parts.path;
222     return str;
223   }
224
225   if (!parts.is_port_wildcard) {
226     str += std::string(kUrlPortSeparator) + parts.port;
227   }
228
229   return str;
230 }
231
232 }  // namespace content_settings