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

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: Test updates Created 8 years, 10 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 standard_scheme_end_pos =
145 bool has_standard_scheme_separator = true; 148 pattern.find(chrome::kStandardSchemeSeparator);
149 bool has_standard_scheme_separator =
150 (standard_scheme_end_pos != std::string::npos);
146 151
147 // Some urls also use ':' alone as the scheme separator. 152 // Some urls also use ':' alone as the scheme separator.
148 if (scheme_end_pos == std::string::npos) { 153 size_t simple_scheme_end_pos = pattern.find(':');
149 scheme_end_pos = pattern.find(':'); 154 bool has_simple_scheme_separator =
150 has_standard_scheme_separator = false; 155 (simple_scheme_end_pos != std::string::npos) &&
151 } 156 (!has_standard_scheme_separator ||
157 simple_scheme_end_pos < standard_scheme_end_pos);
152 158
153 if (scheme_end_pos == std::string::npos) 159 size_t scheme_end_pos;
Aaron Boodman 2012/02/15 21:31:18 Please always initialize primitives. I wish we had
Aaron Boodman 2012/02/15 21:31:18 So is it true at this point that has_simple_scheme
ericu 2012/02/16 01:42:56 Done.
ericu 2012/02/16 01:42:56 No. It used to be true, but now we have "filesyst
160
161 if (has_simple_scheme_separator)
162 scheme_end_pos = simple_scheme_end_pos;
163 else if (has_standard_scheme_separator)
164 scheme_end_pos = standard_scheme_end_pos;
165 else
154 return PARSE_ERROR_MISSING_SCHEME_SEPARATOR; 166 return PARSE_ERROR_MISSING_SCHEME_SEPARATOR;
155 167
156 if (!SetScheme(pattern.substr(0, scheme_end_pos))) 168 if (!SetScheme(pattern.substr(0, scheme_end_pos)))
Aaron Boodman 2012/02/15 21:31:18 Would it be simpler to restructure parsing the sch
ericu 2012/02/16 01:42:56 Thanks for the suggestion; I think it's a lot clea
157 return PARSE_ERROR_INVALID_SCHEME; 169 return PARSE_ERROR_INVALID_SCHEME;
158 170
171 if (!has_simple_scheme_separator && has_standard_scheme_separator &&
Aaron Boodman 2012/02/15 21:31:18 This method is getting pretty hairy. Is it possibl
ericu 2012/02/16 01:42:56 Do you still think it's necessary after the rewrit
172 scheme_ == chrome::kFileSystemScheme)
173 return PARSE_ERROR_WRONG_SCHEME_SEPARATOR;
174
175 if (has_simple_scheme_separator && has_standard_scheme_separator) {
176 if (scheme_ != chrome::kFileSystemScheme)
177 return PARSE_ERROR_WRONG_SCHEME_SEPARATOR;
178 if (!SetInnerScheme(
179 pattern.substr(simple_scheme_end_pos + 1,
180 standard_scheme_end_pos - simple_scheme_end_pos - 1)))
181 return PARSE_ERROR_INVALID_SCHEME;
182 scheme_end_pos = standard_scheme_end_pos;
183 }
184
159 bool standard_scheme = IsStandardScheme(scheme_); 185 bool standard_scheme = IsStandardScheme(scheme_);
160 if (standard_scheme != has_standard_scheme_separator) 186 if (standard_scheme != has_standard_scheme_separator)
161 return PARSE_ERROR_WRONG_SCHEME_SEPARATOR; 187 return PARSE_ERROR_WRONG_SCHEME_SEPARATOR;
162 188
163 // Advance past the scheme separator. 189 // Advance past the scheme separator.
164 scheme_end_pos += 190 scheme_end_pos +=
165 (standard_scheme ? strlen(chrome::kStandardSchemeSeparator) : 1); 191 (has_standard_scheme_separator ?
192 strlen(chrome::kStandardSchemeSeparator) : 1);
166 if (scheme_end_pos >= pattern.size()) 193 if (scheme_end_pos >= pattern.size())
167 return PARSE_ERROR_EMPTY_HOST; 194 return PARSE_ERROR_EMPTY_HOST;
168 195
169 // Parse out the host and path. 196 // Parse out the host and path.
170 size_t host_start_pos = scheme_end_pos; 197 size_t host_start_pos = scheme_end_pos;
171 size_t path_start_pos = 0; 198 size_t path_start_pos = 0;
172 199
173 if (!standard_scheme) { 200 if (!standard_scheme) {
174 path_start_pos = host_start_pos; 201 path_start_pos = host_start_pos;
175 } else if (scheme_ == chrome::kFileScheme) { 202 } else if (scheme_ == chrome::kFileScheme) {
176 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); 203 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
177 if (host_end_pos == std::string::npos) { 204 if (host_end_pos == std::string::npos) {
178 // Allow hostname omission. 205 // Allow hostname omission.
179 // e.g. file://* is interpreted as file:///*, 206 // e.g. file://* is interpreted as file:///*,
180 // file://foo* is interpreted as file:///foo*. 207 // file://foo* is interpreted as file:///foo*.
181 path_start_pos = host_start_pos - 1; 208 path_start_pos = host_start_pos - 1;
182 } else { 209 } else {
183 // Ignore hostname if scheme is file://. 210 // Ignore hostname if scheme is file://.
184 // e.g. file://localhost/foo is equal to file:///foo. 211 // e.g. file://localhost/foo is equal to file:///foo.
185 path_start_pos = host_end_pos; 212 path_start_pos = host_end_pos;
186 } 213 }
214 } else if (scheme_ == chrome::kFileSystemScheme &&
215 inner_scheme_ == chrome::kFileScheme) {
216 // We can't distinguish between a host and a storage type in a
217 // filesystem:file URL, so just let it be part of the path.
218 path_start_pos = host_start_pos;
187 } else { 219 } else {
188 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); 220 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
189 221
190 // Host is required. 222 // Host is required.
191 if (host_start_pos == host_end_pos) 223 if (host_start_pos == host_end_pos)
192 return PARSE_ERROR_EMPTY_HOST; 224 return PARSE_ERROR_EMPTY_HOST;
193 225
194 if (host_end_pos == std::string::npos) 226 if (host_end_pos == std::string::npos)
195 return PARSE_ERROR_EMPTY_PATH; 227 return PARSE_ERROR_EMPTY_PATH;
196 228
(...skipping 26 matching lines...) Expand all
223 // think '*' works as a glob in the host. 255 // think '*' works as a glob in the host.
224 if (host_.find('*') != std::string::npos) 256 if (host_.find('*') != std::string::npos)
225 return PARSE_ERROR_INVALID_HOST_WILDCARD; 257 return PARSE_ERROR_INVALID_HOST_WILDCARD;
226 258
227 return PARSE_SUCCESS; 259 return PARSE_SUCCESS;
228 } 260 }
229 261
230 void URLPattern::SetValidSchemes(int valid_schemes) { 262 void URLPattern::SetValidSchemes(int valid_schemes) {
231 spec_.clear(); 263 spec_.clear();
232 valid_schemes_ = valid_schemes; 264 valid_schemes_ = valid_schemes;
265 valid_inner_schemes_ = valid_schemes;
266 }
267
268 void URLPattern::SetValidInnerSchemes(int valid_schemes) {
269 spec_.clear();
270 valid_inner_schemes_ = valid_schemes;
233 } 271 }
234 272
235 void URLPattern::SetHost(const std::string& host) { 273 void URLPattern::SetHost(const std::string& host) {
236 spec_.clear(); 274 spec_.clear();
237 host_ = host; 275 host_ = host;
238 } 276 }
239 277
240 void URLPattern::SetMatchAllURLs(bool val) { 278 void URLPattern::SetMatchAllURLs(bool val) {
241 spec_.clear(); 279 spec_.clear();
242 match_all_urls_ = val; 280 match_all_urls_ = val;
243 281
244 if (val) { 282 if (val) {
245 match_subdomains_ = true; 283 match_subdomains_ = true;
246 scheme_ = "*"; 284 scheme_ = "*";
247 host_.clear(); 285 host_.clear();
248 SetPath("/*"); 286 SetPath("/*");
249 } 287 }
250 } 288 }
251 289
252 void URLPattern::SetMatchSubdomains(bool val) { 290 void URLPattern::SetMatchSubdomains(bool val) {
253 spec_.clear(); 291 spec_.clear();
254 match_subdomains_ = val; 292 match_subdomains_ = val;
255 } 293 }
256 294
257 bool URLPattern::SetScheme(const std::string& scheme) { 295 bool URLPattern::SetScheme(const std::string& scheme) {
258 spec_.clear(); 296 spec_.clear();
259 scheme_ = scheme; 297 inner_scheme_.clear();
260 if (scheme_ == "*") { 298 if (scheme == "*") {
261 valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS); 299 valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
262 } else if (!IsValidScheme(scheme_)) { 300 } else if (!IsValidScheme(scheme)) {
263 return false; 301 return false;
264 } 302 }
303 scheme_ = scheme;
265 return true; 304 return true;
266 } 305 }
267 306
307 bool URLPattern::SetInnerScheme(const std::string& scheme) {
Aaron Boodman 2012/02/15 21:31:18 It would be more clear to name this param "inner_s
ericu 2012/02/16 01:42:56 Done.
308 spec_.clear();
309 DCHECK(scheme_ == chrome::kFileSystemScheme);
310 if (scheme == "*") {
311 valid_inner_schemes_ = SCHEME_HTTP | SCHEME_HTTPS | SCHEME_FTP |
Aaron Boodman 2012/02/15 21:31:18 This looks weird. In your travels, did you come to
ericu 2012/02/16 01:42:56 It only does so if you're putting in a wildcard.
312 SCHEME_EXTENSION; // Exclude file: and chrome:.
313 } else if (!IsValidInnerScheme(scheme)) {
314 return false;
315 }
316 inner_scheme_ = scheme;
317 return true;
318 }
319
268 bool URLPattern::IsValidScheme(const std::string& scheme) const { 320 bool URLPattern::IsValidScheme(const std::string& scheme) const {
269 if (valid_schemes_ == SCHEME_ALL) 321 if (valid_schemes_ == SCHEME_ALL)
270 return true; 322 return true;
271 323
272 for (size_t i = 0; i < arraysize(kValidSchemes); ++i) { 324 for (size_t i = 0; i < arraysize(kValidSchemes); ++i) {
273 if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i])) 325 if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
274 return true; 326 return true;
275 } 327 }
276 328
277 return false; 329 return false;
278 } 330 }
279 331
332 bool URLPattern::IsValidInnerScheme(const std::string& scheme) const {
333 // kFileSystemScheme is never a valid inner scheme, even if using SCHEME_ALL.
334 if (scheme == chrome::kFileSystemScheme)
335 return false;
336
337 if (valid_inner_schemes_ == SCHEME_ALL)
338 return true;
339
340 for (size_t i = 0; i < arraysize(kValidSchemes); ++i) {
341 if (scheme == kValidSchemes[i] &&
342 (valid_inner_schemes_ & kValidSchemeMasks[i]))
343 return true;
344 }
345
346 return false;
347 }
348
280 void URLPattern::SetPath(const std::string& path) { 349 void URLPattern::SetPath(const std::string& path) {
281 spec_.clear(); 350 spec_.clear();
282 path_ = path; 351 path_ = path;
283 path_escaped_ = path_; 352 path_escaped_ = path_;
284 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\"); 353 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
285 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?"); 354 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
286 } 355 }
287 356
288 bool URLPattern::SetPort(const std::string& port) { 357 bool URLPattern::SetPort(const std::string& port) {
289 spec_.clear(); 358 spec_.clear();
290 if (IsValidPortForScheme(scheme_, port)) { 359 std::string scheme = scheme_;
Aaron Boodman 2012/02/15 21:31:18 More clear to use a ternary operator here?
ericu 2012/02/16 01:42:56 Done.
360 if (scheme == chrome::kFileSystemScheme)
361 scheme = inner_scheme_;
362 if (IsValidPortForScheme(scheme, port)) {
291 port_ = port; 363 port_ = port;
292 return true; 364 return true;
293 } 365 }
294 return false; 366 return false;
295 } 367 }
296 368
297 bool URLPattern::MatchesURL(const GURL& test) const { 369 bool URLPattern::MatchesURL(const GURL& test) const {
298 if (!MatchesScheme(test.scheme())) 370 if (!MatchesScheme(test.scheme()))
299 return false; 371 return false;
300 372
301 if (match_all_urls_) 373 if (match_all_urls_)
302 return true; 374 return true;
303 375
304 return MatchesSecurityOriginHelper(test) && 376 DCHECK(!test.SchemeIsFileSystem() || test.inner_url());
305 MatchesPath(test.PathForRequest()); 377 if (scheme_ == chrome::kFileSystemScheme &&
378 (!test.SchemeIsFileSystem() ||
379 !MatchesInnerScheme(test.inner_url()->scheme())))
380 return false;
381
382 std::string path = test.PathForRequest();
383
384 // Filesystem URLs have the first path segment on the inner_url.
385 if (test.SchemeIsFileSystem())
386 path = test.inner_url()->path() + path;
387
388 return MatchesSecurityOriginHelper(test) && MatchesPath(path);
306 } 389 }
307 390
308 bool URLPattern::MatchesSecurityOrigin(const GURL& test) const { 391 bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
309 if (!MatchesScheme(test.scheme())) 392 if (!MatchesScheme(test.scheme()))
310 return false; 393 return false;
311 394
312 if (match_all_urls_) 395 if (match_all_urls_)
313 return true; 396 return true;
314 397
315 return MatchesSecurityOriginHelper(test); 398 return MatchesSecurityOriginHelper(test);
316 } 399 }
317 400
318 bool URLPattern::MatchesScheme(const std::string& test) const { 401 bool URLPattern::MatchesScheme(const std::string& test) const {
319 if (!IsValidScheme(test)) 402 if (!IsValidScheme(test))
320 return false; 403 return false;
321 404
322 return scheme_ == "*" || test == scheme_; 405 return scheme_ == "*" || test == scheme_;
323 } 406 }
324 407
408 bool URLPattern::MatchesInnerScheme(const std::string& test) const {
409 DCHECK(scheme_ == chrome::kFileSystemScheme);
410 if (!IsValidInnerScheme(test))
411 return false;
412
413 return inner_scheme_ == "*" || test == inner_scheme_;
414 }
415
325 bool URLPattern::MatchesHost(const std::string& host) const { 416 bool URLPattern::MatchesHost(const std::string& host) const {
326 std::string test(chrome::kHttpScheme); 417 std::string test(chrome::kHttpScheme);
327 test += chrome::kStandardSchemeSeparator; 418 test += chrome::kStandardSchemeSeparator;
328 test += host; 419 test += host;
329 test += "/"; 420 test += "/";
330 return MatchesHost(GURL(test)); 421 return MatchesHost(GURL(test));
331 } 422 }
332 423
333 bool URLPattern::MatchesHost(const GURL& test) const { 424 bool URLPattern::MatchesHost(const GURL& test) const {
334 // If the hosts are exactly equal, we have a match. 425 // If the hosts are exactly equal, we have a match.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 if (!spec_.empty()) 471 if (!spec_.empty())
381 return spec_; 472 return spec_;
382 473
383 if (match_all_urls_) { 474 if (match_all_urls_) {
384 spec_ = kAllUrlsPattern; 475 spec_ = kAllUrlsPattern;
385 return spec_; 476 return spec_;
386 } 477 }
387 478
388 bool standard_scheme = IsStandardScheme(scheme_); 479 bool standard_scheme = IsStandardScheme(scheme_);
389 480
390 std::string spec = scheme_ + 481 std::string spec = scheme_;
391 (standard_scheme ? chrome::kStandardSchemeSeparator : ":"); 482 std::string scheme = scheme_;
483 bool add_standard_separator = standard_scheme;
484 if (scheme_ == chrome::kFileSystemScheme) {
485 spec += ":" + inner_scheme_;
486 add_standard_separator = true;
487 standard_scheme = IsStandardScheme(inner_scheme_);
488 scheme = inner_scheme_;
489 }
490 spec += (add_standard_separator ? chrome::kStandardSchemeSeparator : ":");
392 491
393 if (scheme_ != chrome::kFileScheme && standard_scheme) { 492 if (scheme != chrome::kFileScheme && standard_scheme) {
394 if (match_subdomains_) { 493 if (match_subdomains_) {
395 spec += "*"; 494 spec += "*";
396 if (!host_.empty()) 495 if (!host_.empty())
397 spec += "."; 496 spec += ".";
398 } 497 }
399 498
400 if (!host_.empty()) 499 if (!host_.empty())
401 spec += host_; 500 spec += host_;
402 501
403 if (port_ != "*") { 502 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(); 544 for (std::vector<std::string>::const_iterator i = schemes.begin();
446 i != schemes.end(); ++i) { 545 i != schemes.end(); ++i) {
447 if (MatchesScheme(*i)) 546 if (MatchesScheme(*i))
448 return true; 547 return true;
449 } 548 }
450 549
451 return false; 550 return false;
452 } 551 }
453 552
454 bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const { 553 bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
455 // Ignore hostname if scheme is file://. 554 // Ignore hostname if scheme is file:// or filesystem:file://.
456 if (scheme_ != chrome::kFileScheme && !MatchesHost(test)) 555 std::string scheme = scheme_;
556 const GURL* test_url = &test;
557 if (scheme == chrome::kFileSystemScheme) {
558 scheme = inner_scheme_;
559 test_url = test.inner_url();
560 DCHECK(test_url);
561 }
562 if (scheme != chrome::kFileScheme && !MatchesHost(*test_url))
457 return false; 563 return false;
458 564
459 if (!MatchesPort(test.EffectiveIntPort())) 565 if (!MatchesPort(test_url->EffectiveIntPort()))
460 return false; 566 return false;
461 567
462 return true; 568 return true;
463 } 569 }
464 570
465 std::vector<std::string> URLPattern::GetExplicitSchemes() const { 571 std::vector<std::string> URLPattern::GetExplicitSchemes() const {
466 std::vector<std::string> result; 572 std::vector<std::string> result;
467 573
468 if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) { 574 if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
469 result.push_back(scheme_); 575 result.push_back(scheme_);
(...skipping 22 matching lines...) Expand all
492 } 598 }
493 599
494 return result; 600 return result;
495 } 601 }
496 602
497 // static 603 // static
498 const char* URLPattern::GetParseResultString( 604 const char* URLPattern::GetParseResultString(
499 URLPattern::ParseResult parse_result) { 605 URLPattern::ParseResult parse_result) {
500 return kParseResultMessages[parse_result]; 606 return kParseResultMessages[parse_result];
501 } 607 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698