Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.core; | 5 part of dart.core; |
| 6 | 6 |
| 7 // Frequently used character codes. | 7 // Frequently used character codes. |
| 8 const int _SPACE = 0x20; | 8 const int _SPACE = 0x20; |
| 9 const int _PERCENT = 0x25; | 9 const int _PERCENT = 0x25; |
| 10 const int _PLUS = 0x2B; | 10 const int _PLUS = 0x2B; |
| (...skipping 1452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1463 port = _makePort(port, scheme); | 1463 port = _makePort(port, scheme); |
| 1464 bool isFile = (scheme == "file"); | 1464 bool isFile = (scheme == "file"); |
| 1465 if (host == null && | 1465 if (host == null && |
| 1466 (userInfo.isNotEmpty || port != null || isFile)) { | 1466 (userInfo.isNotEmpty || port != null || isFile)) { |
| 1467 host = ""; | 1467 host = ""; |
| 1468 } | 1468 } |
| 1469 bool hasAuthority = (host != null); | 1469 bool hasAuthority = (host != null); |
| 1470 path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, | 1470 path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, |
| 1471 scheme, hasAuthority); | 1471 scheme, hasAuthority); |
| 1472 if (scheme.isEmpty && host == null && !path.startsWith('/')) { | 1472 if (scheme.isEmpty && host == null && !path.startsWith('/')) { |
| 1473 path = _normalizeRelativePath(path); | 1473 path = _normalizeRelativePath(path, scheme.isNotEmpty || host != null); |
|
floitsch
2017/01/12 16:05:49
I generally assign boolean variables to locals fir
Lasse Reichstein Nielsen
2017/01/16 08:17:23
Done.
| |
| 1474 } else { | 1474 } else { |
| 1475 path = _removeDotSegments(path); | 1475 path = _removeDotSegments(path); |
| 1476 } | 1476 } |
| 1477 if (host == null && path.startsWith("//")) { | |
| 1478 host = ""; | |
| 1479 } | |
| 1477 return new _Uri._internal(scheme, userInfo, host, port, | 1480 return new _Uri._internal(scheme, userInfo, host, port, |
| 1478 path, query, fragment); | 1481 path, query, fragment); |
| 1479 } | 1482 } |
| 1480 | 1483 |
| 1481 /// Implementation of [Uri.http]. | 1484 /// Implementation of [Uri.http]. |
| 1482 factory _Uri.http(String authority, | 1485 factory _Uri.http(String authority, |
| 1483 String unencodedPath, | 1486 String unencodedPath, |
| 1484 [Map<String, String> queryParameters]) { | 1487 [Map<String, String> queryParameters]) { |
| 1485 return _makeHttpUri("http", authority, unencodedPath, queryParameters); | 1488 return _makeHttpUri("http", authority, unencodedPath, queryParameters); |
| 1486 } | 1489 } |
| (...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2051 return result; | 2054 return result; |
| 2052 } | 2055 } |
| 2053 | 2056 |
| 2054 /// Performs path normalization (remove dot segments) on a path. | 2057 /// Performs path normalization (remove dot segments) on a path. |
| 2055 /// | 2058 /// |
| 2056 /// If the URI has neither scheme nor authority, it's considered a | 2059 /// If the URI has neither scheme nor authority, it's considered a |
| 2057 /// "pure path" and normalization won't remove leading ".." segments. | 2060 /// "pure path" and normalization won't remove leading ".." segments. |
| 2058 /// Otherwise it follows the RFC 3986 "remove dot segments" algorithm. | 2061 /// Otherwise it follows the RFC 3986 "remove dot segments" algorithm. |
| 2059 static String _normalizePath(String path, String scheme, bool hasAuthority) { | 2062 static String _normalizePath(String path, String scheme, bool hasAuthority) { |
| 2060 if (scheme.isEmpty && !hasAuthority && !path.startsWith('/')) { | 2063 if (scheme.isEmpty && !hasAuthority && !path.startsWith('/')) { |
| 2061 return _normalizeRelativePath(path); | 2064 return _normalizeRelativePath(path, scheme.isNotEmpty || hasAuthority); |
| 2062 } | 2065 } |
| 2063 return _removeDotSegments(path); | 2066 return _removeDotSegments(path); |
| 2064 } | 2067 } |
| 2065 | 2068 |
| 2066 static String _makeQuery( | 2069 static String _makeQuery( |
| 2067 String query, int start, int end, | 2070 String query, int start, int end, |
| 2068 Map<String, dynamic/*String|Iterable<String>*/> queryParameters) { | 2071 Map<String, dynamic/*String|Iterable<String>*/> queryParameters) { |
| 2069 if (query != null) { | 2072 if (query != null) { |
| 2070 if (queryParameters != null) { | 2073 if (queryParameters != null) { |
| 2071 throw new ArgumentError('Both query and queryParameters specified'); | 2074 throw new ArgumentError('Both query and queryParameters specified'); |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2347 } else { | 2350 } else { |
| 2348 output.add(segment); | 2351 output.add(segment); |
| 2349 } | 2352 } |
| 2350 } | 2353 } |
| 2351 if (appendSlash) output.add(""); | 2354 if (appendSlash) output.add(""); |
| 2352 return output.join("/"); | 2355 return output.join("/"); |
| 2353 } | 2356 } |
| 2354 | 2357 |
| 2355 /// Removes all `.` segments and any non-leading `..` segments. | 2358 /// Removes all `.` segments and any non-leading `..` segments. |
| 2356 /// | 2359 /// |
| 2360 /// If the path starts with something that looks like a scheme, | |
| 2361 /// and [allowScheme] is false, the colon is escaped. | |
| 2362 /// | |
| 2357 /// Removing the ".." from a "bar/foo/.." sequence results in "bar/" | 2363 /// Removing the ".." from a "bar/foo/.." sequence results in "bar/" |
| 2358 /// (trailing "/"). If the entire path is removed (because it contains as | 2364 /// (trailing "/"). If the entire path is removed (because it contains as |
| 2359 /// many ".." segments as real segments), the result is "./". | 2365 /// many ".." segments as real segments), the result is "./". |
| 2360 /// This is different from an empty string, which represents "no path", | 2366 /// This is different from an empty string, which represents "no path", |
| 2361 /// when you resolve it against a base URI with a path with a non-empty | 2367 /// when you resolve it against a base URI with a path with a non-empty |
| 2362 /// final segment. | 2368 /// final segment. |
| 2363 static String _normalizeRelativePath(String path) { | 2369 static String _normalizeRelativePath(String path, bool allowScheme) { |
| 2364 assert(!path.startsWith('/')); // Only get called for relative paths. | 2370 assert(!path.startsWith('/')); // Only get called for relative paths. |
| 2365 if (!_mayContainDotSegments(path)) return path; | 2371 if (!_mayContainDotSegments(path)) { |
| 2372 if (!allowScheme) path = _escapeScheme(path); | |
| 2373 return path; | |
| 2374 } | |
| 2366 assert(path.isNotEmpty); // An empty path would not have dot segments. | 2375 assert(path.isNotEmpty); // An empty path would not have dot segments. |
| 2367 List<String> output = []; | 2376 List<String> output = []; |
| 2368 bool appendSlash = false; | 2377 bool appendSlash = false; |
| 2369 for (String segment in path.split("/")) { | 2378 for (String segment in path.split("/")) { |
| 2370 appendSlash = false; | 2379 appendSlash = false; |
| 2371 if (".." == segment) { | 2380 if (".." == segment) { |
| 2372 if (!output.isEmpty && output.last != "..") { | 2381 if (!output.isEmpty && output.last != "..") { |
| 2373 output.removeLast(); | 2382 output.removeLast(); |
| 2374 appendSlash = true; | 2383 appendSlash = true; |
| 2375 } else { | 2384 } else { |
| 2376 output.add(".."); | 2385 output.add(".."); |
| 2377 } | 2386 } |
| 2378 } else if ("." == segment) { | 2387 } else if ("." == segment) { |
| 2379 appendSlash = true; | 2388 appendSlash = true; |
| 2380 } else { | 2389 } else { |
| 2381 output.add(segment); | 2390 output.add(segment); |
| 2382 } | 2391 } |
| 2383 } | 2392 } |
| 2384 if (output.isEmpty || (output.length == 1 && output[0].isEmpty)) { | 2393 if (output.isEmpty || (output.length == 1 && output[0].isEmpty)) { |
| 2385 return "./"; | 2394 return "./"; |
| 2386 } | 2395 } |
| 2387 if (appendSlash || output.last == '..') output.add(""); | 2396 if (appendSlash || output.last == '..') output.add(""); |
| 2397 if (!allowScheme) output[0] = _escapeScheme(output[0]); | |
| 2388 return output.join("/"); | 2398 return output.join("/"); |
| 2389 } | 2399 } |
| 2390 | 2400 |
| 2401 /// If [path] starts with a valid scheme, escape the percent. | |
| 2402 static String _escapeScheme(String path) { | |
| 2403 if (path.length >= 2 && _isAlphabeticCharacter(path.codeUnitAt(0))) { | |
| 2404 for (int i = 1; i < path.length; i++) { | |
| 2405 int char = path.codeUnitAt(i); | |
| 2406 if (char == _COLON) { | |
| 2407 return "${path.substring(0, i)}%3A${path.substring(i + 1)}"; | |
| 2408 } | |
| 2409 if (char > 127 || | |
| 2410 ((_schemeTable[char >> 4] & (1 << (char & 0x0f))) == 0)) { | |
| 2411 break; | |
| 2412 } | |
| 2413 } | |
| 2414 } | |
| 2415 return path; | |
| 2416 } | |
| 2417 | |
| 2391 Uri resolve(String reference) { | 2418 Uri resolve(String reference) { |
| 2392 return resolveUri(Uri.parse(reference)); | 2419 return resolveUri(Uri.parse(reference)); |
| 2393 } | 2420 } |
| 2394 | 2421 |
| 2395 Uri resolveUri(Uri reference) { | 2422 Uri resolveUri(Uri reference) { |
| 2396 // From RFC 3986. | 2423 // From RFC 3986. |
| 2397 String targetScheme; | 2424 String targetScheme; |
| 2398 String targetUserInfo = ""; | 2425 String targetUserInfo = ""; |
| 2399 String targetHost; | 2426 String targetHost; |
| 2400 int targetPort; | 2427 int targetPort; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2452 } | 2479 } |
| 2453 } else { | 2480 } else { |
| 2454 var mergedPath = _mergePaths(this._path, reference.path); | 2481 var mergedPath = _mergePaths(this._path, reference.path); |
| 2455 if (this.hasScheme || this.hasAuthority || this.hasAbsolutePath) { | 2482 if (this.hasScheme || this.hasAuthority || this.hasAbsolutePath) { |
| 2456 targetPath = _removeDotSegments(mergedPath); | 2483 targetPath = _removeDotSegments(mergedPath); |
| 2457 } else { | 2484 } else { |
| 2458 // Non-RFC 3986 behavior. | 2485 // Non-RFC 3986 behavior. |
| 2459 // If both base and reference are relative paths, | 2486 // If both base and reference are relative paths, |
| 2460 // allow the merged path to start with "..". | 2487 // allow the merged path to start with "..". |
| 2461 // The RFC only specifies the case where the base has a scheme. | 2488 // The RFC only specifies the case where the base has a scheme. |
| 2462 targetPath = _normalizeRelativePath(mergedPath); | 2489 targetPath = _normalizeRelativePath(mergedPath, |
| 2490 this.hasScheme || this.hasAuthority); | |
| 2463 } | 2491 } |
| 2464 } | 2492 } |
| 2465 } | 2493 } |
| 2466 if (reference.hasQuery) targetQuery = reference.query; | 2494 if (reference.hasQuery) targetQuery = reference.query; |
| 2467 } | 2495 } |
| 2468 } | 2496 } |
| 2469 } | 2497 } |
| 2470 String fragment = reference.hasFragment ? reference.fragment : null; | 2498 String fragment = reference.hasFragment ? reference.fragment : null; |
| 2471 return new _Uri._internal(targetScheme, | 2499 return new _Uri._internal(targetScheme, |
| 2472 targetUserInfo, | 2500 targetUserInfo, |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2589 UriData get data => (scheme == "data") ? new UriData.fromUri(this) : null; | 2617 UriData get data => (scheme == "data") ? new UriData.fromUri(this) : null; |
| 2590 | 2618 |
| 2591 String toString() { | 2619 String toString() { |
| 2592 return _text ??= _initializeText(); | 2620 return _text ??= _initializeText(); |
| 2593 } | 2621 } |
| 2594 | 2622 |
| 2595 String _initializeText() { | 2623 String _initializeText() { |
| 2596 assert(_text == null); | 2624 assert(_text == null); |
| 2597 StringBuffer sb = new StringBuffer(); | 2625 StringBuffer sb = new StringBuffer(); |
| 2598 if (scheme.isNotEmpty) sb..write(scheme)..write(":"); | 2626 if (scheme.isNotEmpty) sb..write(scheme)..write(":"); |
| 2599 if (hasAuthority || path.startsWith("//") || (scheme == "file")) { | 2627 if (hasAuthority || (scheme == "file")) { |
| 2600 // File URIS always have the authority, even if it is empty. | 2628 // File URIS always have the authority, even if it is empty. |
| 2601 // The empty URI means "localhost". | 2629 // The empty URI means "localhost". |
| 2602 sb.write("//"); | 2630 sb.write("//"); |
| 2603 _writeAuthority(sb); | 2631 _writeAuthority(sb); |
| 2604 } | 2632 } |
| 2605 sb.write(path); | 2633 sb.write(path); |
| 2606 if (_query != null) sb..write("?")..write(_query); | 2634 if (_query != null) sb..write("?")..write(_query); |
| 2607 if (_fragment != null) sb..write("#")..write(_fragment); | 2635 if (_fragment != null) sb..write("#")..write(_fragment); |
| 2608 return sb.toString(); | 2636 return sb.toString(); |
| 2609 } | 2637 } |
| (...skipping 1858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4468 int delta = (text.codeUnitAt(start + 4) ^ _COLON) * 3; | 4496 int delta = (text.codeUnitAt(start + 4) ^ _COLON) * 3; |
| 4469 delta |= text.codeUnitAt(start) ^ 0x64 /*d*/; | 4497 delta |= text.codeUnitAt(start) ^ 0x64 /*d*/; |
| 4470 delta |= text.codeUnitAt(start + 1) ^ 0x61 /*a*/; | 4498 delta |= text.codeUnitAt(start + 1) ^ 0x61 /*a*/; |
| 4471 delta |= text.codeUnitAt(start + 2) ^ 0x74 /*t*/; | 4499 delta |= text.codeUnitAt(start + 2) ^ 0x74 /*t*/; |
| 4472 delta |= text.codeUnitAt(start + 3) ^ 0x61 /*a*/; | 4500 delta |= text.codeUnitAt(start + 3) ^ 0x61 /*a*/; |
| 4473 return delta; | 4501 return delta; |
| 4474 } | 4502 } |
| 4475 | 4503 |
| 4476 /// Helper function returning the length of a string, or `0` for `null`. | 4504 /// Helper function returning the length of a string, or `0` for `null`. |
| 4477 int _stringOrNullLength(String s) => (s == null) ? 0 : s.length; | 4505 int _stringOrNullLength(String s) => (s == null) ? 0 : s.length; |
| OLD | NEW |