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 |