Index: sdk/lib/core/uri.dart |
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart |
index 3fe4100dbf366e111d90af934ba765a68b785b87..de2c38bbf8ab6558ca07e00c739b26f399b76b8f 100644 |
--- a/sdk/lib/core/uri.dart |
+++ b/sdk/lib/core/uri.dart |
@@ -705,7 +705,21 @@ class Uri { |
*/ |
factory Uri.file(String path, {bool windows}) { |
windows = (windows == null) ? Uri._isWindows : windows; |
- return windows ? _makeWindowsFileUrl(path) : _makeFileUri(path); |
+ return windows ? _makeWindowsFileUrl(path, false) |
+ : _makeFileUri(path, false); |
+ } |
+ |
+ /** |
+ * Like [Uri.file] except that a non-empty URI path ends in a slash. |
+ * |
+ * If [path] is not empty, and it doesn't end in a directory separator, |
+ * then a slash is added to the returned URI's path. |
+ * In all other cases, the result is the same as returned by `Uri.file`. |
+ */ |
+ factory Uri.directory(String path, {bool windows}) { |
+ windows = (windows == null) ? Uri._isWindows : windows; |
+ return windows ? _makeWindowsFileUrl(path, true) |
+ : _makeFileUri(path, true); |
} |
/** |
@@ -762,18 +776,24 @@ class Uri { |
} |
} |
- static _makeFileUri(String path) { |
+ static _makeFileUri(String path, bool slashTerminated) { |
const String sep = "/"; |
+ var segments = path.split(sep); |
+ if (slashTerminated && |
+ segments.isNotEmpty && |
+ segments.last.isNotEmpty) { |
+ segments.add(""); // Extra separator at end. |
+ } |
if (path.startsWith(sep)) { |
// Absolute file:// URI. |
- return new Uri(scheme: "file", pathSegments: path.split(sep)); |
+ return new Uri(scheme: "file", pathSegments: segments); |
} else { |
// Relative URI. |
- return new Uri(pathSegments: path.split(sep)); |
+ return new Uri(pathSegments: segments); |
} |
} |
- static _makeWindowsFileUrl(String path) { |
+ static _makeWindowsFileUrl(String path, bool slashTerminated) { |
if (path.startsWith(r"\\?\")) { |
if (path.startsWith(r"UNC\", 4)) { |
path = path.replaceRange(0, 7, r'\'); |
@@ -798,6 +818,10 @@ class Uri { |
} |
// Absolute file://C:/ URI. |
var pathSegments = path.split(sep); |
+ if (slashTerminated && |
+ pathSegments.last.isNotEmpty) { |
+ pathSegments.add(""); // Extra separator at end. |
+ } |
_checkWindowsPathReservedCharacters(pathSegments, true, 1); |
return new Uri(scheme: "file", pathSegments: pathSegments); |
} |
@@ -812,11 +836,19 @@ class Uri { |
(pathStart < 0) ? "" : path.substring(pathStart + 1); |
var pathSegments = pathPart.split(sep); |
_checkWindowsPathReservedCharacters(pathSegments, true); |
+ if (slashTerminated && |
+ pathSegments.last.isNotEmpty) { |
+ pathSegments.add(""); // Extra separator at end. |
+ } |
return new Uri( |
scheme: "file", host: hostPart, pathSegments: pathSegments); |
} else { |
// Absolute file:// URI. |
var pathSegments = path.split(sep); |
+ if (slashTerminated && |
+ pathSegments.last.isNotEmpty) { |
+ pathSegments.add(""); // Extra separator at end. |
+ } |
_checkWindowsPathReservedCharacters(pathSegments, true); |
return new Uri(scheme: "file", pathSegments: pathSegments); |
} |
@@ -824,6 +856,11 @@ class Uri { |
// Relative URI. |
var pathSegments = path.split(sep); |
_checkWindowsPathReservedCharacters(pathSegments, true); |
+ if (slashTerminated && |
+ pathSegments.isNotEmpty && |
+ pathSegments.last.isNotEmpty) { |
+ pathSegments.add(""); // Extra separator at end. |
+ } |
return new Uri(pathSegments: pathSegments); |
} |
} |