Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: chrome/common/extensions/url_pattern.cc

Issue 7811006: Add full support for filesystem URLs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added TODO for markusheintz Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/common/extensions/url_pattern.h" 5 #include "chrome/common/extensions/url_pattern.h"
6 6
7 #include "base/string_number_conversions.h" 7 #include "base/string_number_conversions.h"
8 #include "base/string_piece.h" 8 #include "base/string_piece.h"
9 #include "base/string_split.h" 9 #include "base/string_split.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 int parsed_port = url_parse::PORT_UNSPECIFIED; 89 int parsed_port = url_parse::PORT_UNSPECIFIED;
90 if (!base::StringToInt(port, &parsed_port)) 90 if (!base::StringToInt(port, &parsed_port))
91 return false; 91 return false;
92 return (parsed_port >= 0) && (parsed_port < 65536); 92 return (parsed_port >= 0) && (parsed_port < 65536);
93 } 93 }
94 94
95 } // namespace 95 } // namespace
96 96
97 URLPattern::URLPattern() 97 URLPattern::URLPattern()
98 : valid_schemes_(SCHEME_NONE), 98 : valid_schemes_(SCHEME_NONE),
99 valid_inner_schemes_(SCHEME_NONE),
99 match_all_urls_(false), 100 match_all_urls_(false),
100 match_subdomains_(false), 101 match_subdomains_(false),
101 port_("*") {} 102 port_("*") {}
102 103
103 URLPattern::URLPattern(int valid_schemes) 104 URLPattern::URLPattern(int valid_schemes)
104 : valid_schemes_(valid_schemes), 105 : valid_schemes_(valid_schemes),
106 valid_inner_schemes_(valid_schemes),
105 match_all_urls_(false), 107 match_all_urls_(false),
106 match_subdomains_(false), 108 match_subdomains_(false),
107 port_("*") {} 109 port_("*") {}
108 110
109 URLPattern::URLPattern(int valid_schemes, const std::string& pattern) 111 URLPattern::URLPattern(int valid_schemes, const std::string& pattern)
110 // Strict error checking is used, because this constructor is only 112 // Strict error checking is used, because this constructor is only
111 // appropriate when we know |pattern| is valid. 113 // appropriate when we know |pattern| is valid.
112 : valid_schemes_(valid_schemes), 114 : valid_schemes_(valid_schemes),
115 valid_inner_schemes_(valid_schemes),
113 match_all_urls_(false), 116 match_all_urls_(false),
114 match_subdomains_(false), 117 match_subdomains_(false),
115 port_("*") { 118 port_("*") {
116 if (PARSE_SUCCESS != Parse(pattern)) 119 if (PARSE_SUCCESS != Parse(pattern))
117 NOTREACHED() << "URLPattern is invalid: " << pattern; 120 NOTREACHED() << "URLPattern is invalid: " << pattern;
118 } 121 }
119 122
120 URLPattern::~URLPattern() { 123 URLPattern::~URLPattern() {
121 } 124 }
122 125
(...skipping 11 matching lines...) Expand all
134 SetMatchSubdomains(false); 137 SetMatchSubdomains(false);
135 SetPort("*"); 138 SetPort("*");
136 139
137 // Special case pattern to match every valid URL. 140 // Special case pattern to match every valid URL.
138 if (pattern == kAllUrlsPattern) { 141 if (pattern == kAllUrlsPattern) {
139 SetMatchAllURLs(true); 142 SetMatchAllURLs(true);
140 return PARSE_SUCCESS; 143 return PARSE_SUCCESS;
141 } 144 }
142 145
143 // Parse out the scheme. 146 // Parse out the scheme.
144 size_t scheme_end_pos = pattern.find(chrome::kStandardSchemeSeparator); 147 size_t scheme_end_pos = pattern.find(':');
145 bool has_standard_scheme_separator = true;
146
147 // Some urls also use ':' alone as the scheme separator.
148 if (scheme_end_pos == std::string::npos) {
149 scheme_end_pos = pattern.find(':');
150 has_standard_scheme_separator = false;
151 }
152
153 if (scheme_end_pos == std::string::npos) 148 if (scheme_end_pos == std::string::npos)
154 return PARSE_ERROR_MISSING_SCHEME_SEPARATOR; 149 return PARSE_ERROR_MISSING_SCHEME_SEPARATOR;
155 150
151 bool has_standard_scheme_separator = false;
152 if (scheme_end_pos + 2 < pattern.length() &&
153 pattern[scheme_end_pos + 1] == '/' &&
154 pattern[scheme_end_pos + 2] == '/') {
155 has_standard_scheme_separator = true;
156 }
157
156 if (!SetScheme(pattern.substr(0, scheme_end_pos))) 158 if (!SetScheme(pattern.substr(0, scheme_end_pos)))
157 return PARSE_ERROR_INVALID_SCHEME; 159 return PARSE_ERROR_INVALID_SCHEME;
158 160
159 bool standard_scheme = IsStandardScheme(scheme_); 161 bool standard_scheme = IsStandardScheme(scheme_);
162
163 if (scheme_ == chrome::kFileSystemScheme) {
Aaron Boodman 2012/03/12 23:17:13 Yeah, would prefer this was something like if (Sup
ericu 2012/03/13 21:58:47 Done.
164 size_t inner_scheme_start_pos = scheme_end_pos + 1;
165 scheme_end_pos = pattern.find(chrome::kStandardSchemeSeparator,
166 inner_scheme_start_pos);
167 if (scheme_end_pos == std::string::npos)
168 return PARSE_ERROR_MISSING_SCHEME_SEPARATOR;
169 has_standard_scheme_separator = true;
170 if (!SetInnerScheme(
171 pattern.substr(inner_scheme_start_pos,
172 scheme_end_pos - inner_scheme_start_pos)))
173 return PARSE_ERROR_INVALID_SCHEME;
Aaron Boodman 2012/03/12 23:17:13 PARSE_ERROR_INVALID_INNER_SCHEME seems better here
ericu 2012/03/13 21:58:47 Done.
174 standard_scheme = IsStandardScheme(inner_scheme_);
175 }
176
160 if (standard_scheme != has_standard_scheme_separator) 177 if (standard_scheme != has_standard_scheme_separator)
Aaron Boodman 2012/03/12 23:17:13 I still think this method has gotten too long and
ericu 2012/03/13 21:58:47 Done.
161 return PARSE_ERROR_WRONG_SCHEME_SEPARATOR; 178 return PARSE_ERROR_WRONG_SCHEME_SEPARATOR;
162 179
163 // Advance past the scheme separator. 180 // Advance past the scheme separator.
164 scheme_end_pos += 181 scheme_end_pos +=
165 (standard_scheme ? strlen(chrome::kStandardSchemeSeparator) : 1); 182 (has_standard_scheme_separator ?
183 strlen(chrome::kStandardSchemeSeparator) : 1);
166 if (scheme_end_pos >= pattern.size()) 184 if (scheme_end_pos >= pattern.size())
167 return PARSE_ERROR_EMPTY_HOST; 185 return PARSE_ERROR_EMPTY_HOST;
168 186
169 // Parse out the host and path. 187 // Parse out the host and path.
170 size_t host_start_pos = scheme_end_pos; 188 size_t host_start_pos = scheme_end_pos;
171 size_t path_start_pos = 0; 189 size_t path_start_pos = 0;
172 190
173 if (!standard_scheme) { 191 if (!standard_scheme) {
174 path_start_pos = host_start_pos; 192 path_start_pos = host_start_pos;
175 } else if (scheme_ == chrome::kFileScheme) { 193 } else if (scheme_ == chrome::kFileScheme) {
176 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); 194 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
177 if (host_end_pos == std::string::npos) { 195 if (host_end_pos == std::string::npos) {
178 // Allow hostname omission. 196 // Allow hostname omission.
179 // e.g. file://* is interpreted as file:///*, 197 // e.g. file://* is interpreted as file:///*,
180 // file://foo* is interpreted as file:///foo*. 198 // file://foo* is interpreted as file:///foo*.
181 path_start_pos = host_start_pos - 1; 199 path_start_pos = host_start_pos - 1;
182 } else { 200 } else {
183 // Ignore hostname if scheme is file://. 201 // Ignore hostname if scheme is file://.
184 // e.g. file://localhost/foo is equal to file:///foo. 202 // e.g. file://localhost/foo is equal to file:///foo.
185 path_start_pos = host_end_pos; 203 path_start_pos = host_end_pos;
186 } 204 }
205 } else if (scheme_ == chrome::kFileSystemScheme &&
206 inner_scheme_ == chrome::kFileScheme) {
207 // We can't distinguish between a host and a storage type in a
208 // filesystem:file URL, so just let it be part of the path.
209 path_start_pos = host_start_pos;
187 } else { 210 } else {
188 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); 211 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
189 212
190 // Host is required. 213 // Host is required.
191 if (host_start_pos == host_end_pos) 214 if (host_start_pos == host_end_pos)
192 return PARSE_ERROR_EMPTY_HOST; 215 return PARSE_ERROR_EMPTY_HOST;
193 216
194 if (host_end_pos == std::string::npos) 217 if (host_end_pos == std::string::npos)
195 return PARSE_ERROR_EMPTY_PATH; 218 return PARSE_ERROR_EMPTY_PATH;
196 219
(...skipping 26 matching lines...) Expand all
223 // think '*' works as a glob in the host. 246 // think '*' works as a glob in the host.
224 if (host_.find('*') != std::string::npos) 247 if (host_.find('*') != std::string::npos)
225 return PARSE_ERROR_INVALID_HOST_WILDCARD; 248 return PARSE_ERROR_INVALID_HOST_WILDCARD;
226 249
227 return PARSE_SUCCESS; 250 return PARSE_SUCCESS;
228 } 251 }
229 252
230 void URLPattern::SetValidSchemes(int valid_schemes) { 253 void URLPattern::SetValidSchemes(int valid_schemes) {
231 spec_.clear(); 254 spec_.clear();
232 valid_schemes_ = valid_schemes; 255 valid_schemes_ = valid_schemes;
256 valid_inner_schemes_ = valid_schemes;
257 }
258
259 void URLPattern::SetValidInnerSchemes(int valid_schemes) {
260 spec_.clear();
261 valid_inner_schemes_ = valid_schemes;
233 } 262 }
234 263
235 void URLPattern::SetHost(const std::string& host) { 264 void URLPattern::SetHost(const std::string& host) {
236 spec_.clear(); 265 spec_.clear();
237 host_ = host; 266 host_ = host;
238 } 267 }
239 268
240 void URLPattern::SetMatchAllURLs(bool val) { 269 void URLPattern::SetMatchAllURLs(bool val) {
241 spec_.clear(); 270 spec_.clear();
242 match_all_urls_ = val; 271 match_all_urls_ = val;
243 272
244 if (val) { 273 if (val) {
245 match_subdomains_ = true; 274 match_subdomains_ = true;
246 scheme_ = "*"; 275 scheme_ = "*";
247 host_.clear(); 276 host_.clear();
248 SetPath("/*"); 277 SetPath("/*");
249 } 278 }
250 } 279 }
251 280
252 void URLPattern::SetMatchSubdomains(bool val) { 281 void URLPattern::SetMatchSubdomains(bool val) {
253 spec_.clear(); 282 spec_.clear();
254 match_subdomains_ = val; 283 match_subdomains_ = val;
255 } 284 }
256 285
257 bool URLPattern::SetScheme(const std::string& scheme) { 286 bool URLPattern::SetScheme(const std::string& scheme) {
258 spec_.clear(); 287 spec_.clear();
259 scheme_ = scheme; 288 inner_scheme_.clear();
260 if (scheme_ == "*") { 289 if (scheme == "*") {
261 valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS); 290 valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
262 } else if (!IsValidScheme(scheme_)) { 291 } else if (!IsValidScheme(scheme)) {
263 return false; 292 return false;
264 } 293 }
294 scheme_ = scheme;
265 return true; 295 return true;
266 } 296 }
267 297
298 bool URLPattern::SetInnerScheme(const std::string& inner_scheme) {
299 spec_.clear();
300 DCHECK(scheme_ == chrome::kFileSystemScheme);
301 if (inner_scheme == "*") {
302 valid_inner_schemes_ = SCHEME_HTTP | SCHEME_HTTPS | SCHEME_FTP |
Aaron Boodman 2012/03/12 23:17:13 I am not sure why SetScheme modifies the valid sch
Aaron Boodman 2012/03/12 23:17:13 Why this particular interpretation of "*"? Note th
ericu 2012/03/13 21:58:47 I implemented it based on the comment in url_patte
ericu 2012/03/13 21:58:47 I'm OK with changing the behavior--there aren't al
303 SCHEME_EXTENSION; // Exclude file: and chrome:.
304 } else if (!IsValidInnerScheme(inner_scheme)) {
305 return false;
306 }
307 inner_scheme_ = inner_scheme;
308 return true;
309 }
310
268 bool URLPattern::IsValidScheme(const std::string& scheme) const { 311 bool URLPattern::IsValidScheme(const std::string& scheme) const {
269 if (valid_schemes_ == SCHEME_ALL) 312 if (valid_schemes_ == SCHEME_ALL)
270 return true; 313 return true;
271 314
272 for (size_t i = 0; i < arraysize(kValidSchemes); ++i) { 315 for (size_t i = 0; i < arraysize(kValidSchemes); ++i) {
273 if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i])) 316 if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
274 return true; 317 return true;
275 } 318 }
276 319
277 return false; 320 return false;
278 } 321 }
279 322
323 bool URLPattern::IsValidInnerScheme(const std::string& scheme) const {
324 // kFileSystemScheme is never a valid inner scheme, even if using SCHEME_ALL.
325 if (scheme == chrome::kFileSystemScheme)
326 return false;
327
328 if (valid_inner_schemes_ == SCHEME_ALL)
329 return true;
330
331 for (size_t i = 0; i < arraysize(kValidSchemes); ++i) {
332 if (scheme == kValidSchemes[i] &&
333 (valid_inner_schemes_ & kValidSchemeMasks[i]))
334 return true;
335 }
336
337 return false;
338 }
339
280 void URLPattern::SetPath(const std::string& path) { 340 void URLPattern::SetPath(const std::string& path) {
281 spec_.clear(); 341 spec_.clear();
282 path_ = path; 342 path_ = path;
283 path_escaped_ = path_; 343 path_escaped_ = path_;
284 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\"); 344 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
285 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?"); 345 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
286 } 346 }
287 347
288 bool URLPattern::SetPort(const std::string& port) { 348 bool URLPattern::SetPort(const std::string& port) {
289 spec_.clear(); 349 spec_.clear();
290 if (IsValidPortForScheme(scheme_, port)) { 350 std::string scheme =
351 (scheme_ == chrome::kFileSystemScheme) ? inner_scheme_ : scheme_;
352 if (IsValidPortForScheme(scheme, port)) {
291 port_ = port; 353 port_ = port;
292 return true; 354 return true;
293 } 355 }
294 return false; 356 return false;
295 } 357 }
296 358
297 bool URLPattern::MatchesURL(const GURL& test) const { 359 bool URLPattern::MatchesURL(const GURL& test) const {
298 if (!MatchesScheme(test.scheme())) 360 if (!MatchesScheme(test.scheme()))
299 return false; 361 return false;
300 362
301 if (match_all_urls_) 363 if (match_all_urls_)
302 return true; 364 return true;
303 365
304 return MatchesSecurityOriginHelper(test) && 366 DCHECK(!test.SchemeIsFileSystem() || test.inner_url());
305 MatchesPath(test.PathForRequest()); 367 if (scheme_ == chrome::kFileSystemScheme &&
368 (!test.SchemeIsFileSystem() ||
369 !MatchesInnerScheme(test.inner_url()->scheme())))
Aaron Boodman 2012/03/12 23:17:13 Style guide requires curly braces here.
ericu 2012/03/13 21:58:47 Done.
370 return false;
371
372 std::string path = test.PathForRequest();
373
374 // Filesystem URLs have the first path segment on the inner_url.
375 if (test.SchemeIsFileSystem())
376 path = test.inner_url()->path() + path;
377
378 return MatchesSecurityOriginHelper(test) && MatchesPath(path);
306 } 379 }
307 380
308 bool URLPattern::MatchesSecurityOrigin(const GURL& test) const { 381 bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
309 if (!MatchesScheme(test.scheme())) 382 if (!MatchesScheme(test.scheme()))
310 return false; 383 return false;
311 384
312 if (match_all_urls_) 385 if (match_all_urls_)
313 return true; 386 return true;
314 387
315 return MatchesSecurityOriginHelper(test); 388 return MatchesSecurityOriginHelper(test);
316 } 389 }
317 390
318 bool URLPattern::MatchesScheme(const std::string& test) const { 391 bool URLPattern::MatchesScheme(const std::string& test) const {
319 if (!IsValidScheme(test)) 392 if (!IsValidScheme(test))
320 return false; 393 return false;
321 394
322 return scheme_ == "*" || test == scheme_; 395 return scheme_ == "*" || test == scheme_;
323 } 396 }
324 397
398 bool URLPattern::MatchesInnerScheme(const std::string& test) const {
399 DCHECK(scheme_ == chrome::kFileSystemScheme);
400 if (!IsValidInnerScheme(test))
401 return false;
402
403 return inner_scheme_ == "*" || test == inner_scheme_;
404 }
405
325 bool URLPattern::MatchesHost(const std::string& host) const { 406 bool URLPattern::MatchesHost(const std::string& host) const {
326 std::string test(chrome::kHttpScheme); 407 std::string test(chrome::kHttpScheme);
327 test += chrome::kStandardSchemeSeparator; 408 test += chrome::kStandardSchemeSeparator;
328 test += host; 409 test += host;
329 test += "/"; 410 test += "/";
330 return MatchesHost(GURL(test)); 411 return MatchesHost(GURL(test));
331 } 412 }
332 413
333 bool URLPattern::MatchesHost(const GURL& test) const { 414 bool URLPattern::MatchesHost(const GURL& test) const {
334 // If the hosts are exactly equal, we have a match. 415 // If the hosts are exactly equal, we have a match.
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 459
379 const std::string& URLPattern::GetAsString() const { 460 const std::string& URLPattern::GetAsString() const {
380 if (!spec_.empty()) 461 if (!spec_.empty())
381 return spec_; 462 return spec_;
382 463
383 if (match_all_urls_) { 464 if (match_all_urls_) {
384 spec_ = kAllUrlsPattern; 465 spec_ = kAllUrlsPattern;
385 return spec_; 466 return spec_;
386 } 467 }
387 468
388 bool standard_scheme = IsStandardScheme(scheme_); 469 bool standard_scheme = IsStandardScheme(scheme_);
Aaron Boodman 2012/03/12 23:17:13 Can you rename this to 'is_standard_scheme' while
ericu 2012/03/13 21:58:47 Done.
389 470
390 std::string spec = scheme_ + 471 std::string spec = scheme_;
391 (standard_scheme ? chrome::kStandardSchemeSeparator : ":"); 472 std::string scheme = scheme_;
473 bool add_standard_separator = standard_scheme;
474 if (scheme_ == chrome::kFileSystemScheme) {
475 spec += ":" + inner_scheme_;
476 add_standard_separator = true;
477 standard_scheme = IsStandardScheme(inner_scheme_);
478 scheme = inner_scheme_;
479 }
480 spec += (add_standard_separator ? chrome::kStandardSchemeSeparator : ":");
392 481
393 if (scheme_ != chrome::kFileScheme && standard_scheme) { 482 if (scheme != chrome::kFileScheme && standard_scheme) {
394 if (match_subdomains_) { 483 if (match_subdomains_) {
395 spec += "*"; 484 spec += "*";
396 if (!host_.empty()) 485 if (!host_.empty())
397 spec += "."; 486 spec += ".";
398 } 487 }
399 488
400 if (!host_.empty()) 489 if (!host_.empty())
401 spec += host_; 490 spec += host_;
402 491
403 if (port_ != "*") { 492 if (port_ != "*") {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 for (std::vector<std::string>::const_iterator i = schemes.begin(); 534 for (std::vector<std::string>::const_iterator i = schemes.begin();
446 i != schemes.end(); ++i) { 535 i != schemes.end(); ++i) {
447 if (MatchesScheme(*i)) 536 if (MatchesScheme(*i))
448 return true; 537 return true;
449 } 538 }
450 539
451 return false; 540 return false;
452 } 541 }
453 542
454 bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const { 543 bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
455 // Ignore hostname if scheme is file://. 544 // Ignore hostname if scheme is file:// or filesystem:file://.
456 if (scheme_ != chrome::kFileScheme && !MatchesHost(test)) 545 std::string scheme = scheme_;
546 const GURL* test_url = &test;
547 if (scheme == chrome::kFileSystemScheme) {
548 scheme = inner_scheme_;
549 test_url = test.inner_url();
550 DCHECK(test_url);
551 }
552 if (scheme != chrome::kFileScheme && !MatchesHost(*test_url))
457 return false; 553 return false;
458 554
459 if (!MatchesPort(test.EffectiveIntPort())) 555 if (!MatchesPort(test_url->EffectiveIntPort()))
460 return false; 556 return false;
461 557
462 return true; 558 return true;
463 } 559 }
464 560
465 std::vector<std::string> URLPattern::GetExplicitSchemes() const { 561 std::vector<std::string> URLPattern::GetExplicitSchemes() const {
466 std::vector<std::string> result; 562 std::vector<std::string> result;
467 563
468 if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) { 564 if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
469 result.push_back(scheme_); 565 result.push_back(scheme_);
(...skipping 22 matching lines...) Expand all
492 } 588 }
493 589
494 return result; 590 return result;
495 } 591 }
496 592
497 // static 593 // static
498 const char* URLPattern::GetParseResultString( 594 const char* URLPattern::GetParseResultString(
499 URLPattern::ParseResult parse_result) { 595 URLPattern::ParseResult parse_result) {
500 return kParseResultMessages[parse_result]; 596 return kParseResultMessages[parse_result];
501 } 597 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698