Index: sdk/lib/core/uri.dart |
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart |
index 847521ac48b1f52cf89d2a3a09bbbed59e54a671..fa7d01bee76617b64085856b948cf738d2539b55 100644 |
--- a/sdk/lib/core/uri.dart |
+++ b/sdk/lib/core/uri.dart |
@@ -1470,10 +1470,13 @@ class _Uri implements Uri { |
path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, |
scheme, hasAuthority); |
if (scheme.isEmpty && host == null && !path.startsWith('/')) { |
- path = _normalizeRelativePath(path); |
+ 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.
|
} else { |
path = _removeDotSegments(path); |
} |
+ if (host == null && path.startsWith("//")) { |
+ host = ""; |
+ } |
return new _Uri._internal(scheme, userInfo, host, port, |
path, query, fragment); |
} |
@@ -2058,7 +2061,7 @@ class _Uri implements Uri { |
/// Otherwise it follows the RFC 3986 "remove dot segments" algorithm. |
static String _normalizePath(String path, String scheme, bool hasAuthority) { |
if (scheme.isEmpty && !hasAuthority && !path.startsWith('/')) { |
- return _normalizeRelativePath(path); |
+ return _normalizeRelativePath(path, scheme.isNotEmpty || hasAuthority); |
} |
return _removeDotSegments(path); |
} |
@@ -2354,15 +2357,21 @@ class _Uri implements Uri { |
/// Removes all `.` segments and any non-leading `..` segments. |
/// |
+ /// If the path starts with something that looks like a scheme, |
+ /// and [allowScheme] is false, the colon is escaped. |
+ /// |
/// Removing the ".." from a "bar/foo/.." sequence results in "bar/" |
/// (trailing "/"). If the entire path is removed (because it contains as |
/// many ".." segments as real segments), the result is "./". |
/// This is different from an empty string, which represents "no path", |
/// when you resolve it against a base URI with a path with a non-empty |
/// final segment. |
- static String _normalizeRelativePath(String path) { |
+ static String _normalizeRelativePath(String path, bool allowScheme) { |
assert(!path.startsWith('/')); // Only get called for relative paths. |
- if (!_mayContainDotSegments(path)) return path; |
+ if (!_mayContainDotSegments(path)) { |
+ if (!allowScheme) path = _escapeScheme(path); |
+ return path; |
+ } |
assert(path.isNotEmpty); // An empty path would not have dot segments. |
List<String> output = []; |
bool appendSlash = false; |
@@ -2385,9 +2394,27 @@ class _Uri implements Uri { |
return "./"; |
} |
if (appendSlash || output.last == '..') output.add(""); |
+ if (!allowScheme) output[0] = _escapeScheme(output[0]); |
return output.join("/"); |
} |
+ /// If [path] starts with a valid scheme, escape the percent. |
+ static String _escapeScheme(String path) { |
+ if (path.length >= 2 && _isAlphabeticCharacter(path.codeUnitAt(0))) { |
+ for (int i = 1; i < path.length; i++) { |
+ int char = path.codeUnitAt(i); |
+ if (char == _COLON) { |
+ return "${path.substring(0, i)}%3A${path.substring(i + 1)}"; |
+ } |
+ if (char > 127 || |
+ ((_schemeTable[char >> 4] & (1 << (char & 0x0f))) == 0)) { |
+ break; |
+ } |
+ } |
+ } |
+ return path; |
+ } |
+ |
Uri resolve(String reference) { |
return resolveUri(Uri.parse(reference)); |
} |
@@ -2459,7 +2486,8 @@ class _Uri implements Uri { |
// If both base and reference are relative paths, |
// allow the merged path to start with "..". |
// The RFC only specifies the case where the base has a scheme. |
- targetPath = _normalizeRelativePath(mergedPath); |
+ targetPath = _normalizeRelativePath(mergedPath, |
+ this.hasScheme || this.hasAuthority); |
} |
} |
} |
@@ -2596,7 +2624,7 @@ class _Uri implements Uri { |
assert(_text == null); |
StringBuffer sb = new StringBuffer(); |
if (scheme.isNotEmpty) sb..write(scheme)..write(":"); |
- if (hasAuthority || path.startsWith("//") || (scheme == "file")) { |
+ if (hasAuthority || (scheme == "file")) { |
// File URIS always have the authority, even if it is empty. |
// The empty URI means "localhost". |
sb.write("//"); |