| Index: sdk/lib/core/uri.dart
|
| diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
|
| index d7f911bfa55d98e782e3be82b6730191046c91b2..847521ac48b1f52cf89d2a3a09bbbed59e54a671 100644
|
| --- a/sdk/lib/core/uri.dart
|
| +++ b/sdk/lib/core/uri.dart
|
| @@ -4323,10 +4323,6 @@ class _SimpleUri implements Uri {
|
| base._schemeCache);
|
| }
|
| // Merge paths.
|
| - if (base._uri.startsWith("../", base._pathStart)) {
|
| - // Complex rare case, go slow.
|
| - return _toNonSimple().resolveUri(ref);
|
| - }
|
|
|
| // The RFC 3986 algorithm merges the base path without its final segment
|
| // (anything after the final "/", or everything if the base path doesn't
|
| @@ -4341,39 +4337,53 @@ class _SimpleUri implements Uri {
|
| String refUri = ref._uri;
|
| int baseStart = base._pathStart;
|
| int baseEnd = base._queryStart;
|
| + while (baseUri.startsWith("../", baseStart)) baseStart += 3;
|
| int refStart = ref._pathStart;
|
| int refEnd = ref._queryStart;
|
| - int backCount = 1;
|
| -
|
| - int slashCount = 0;
|
|
|
| - // Count leading ".." segments in reference path.
|
| + /// Count of leading ".." segments in reference path.
|
| + /// The count is decremented when the segment is matched with a
|
| + /// segment of the base path, and both are then omitted from the result.
|
| + int backCount = 0;
|
| + /// Count "../" segments and advance `refStart` to after the segments.
|
| while (refStart + 3 <= refEnd && refUri.startsWith("../", refStart)) {
|
| refStart += 3;
|
| backCount += 1;
|
| }
|
|
|
| // Extra slash inserted between base and reference path parts if
|
| - // the base path contains any slashes.
|
| + // the base path contains any slashes, or empty string if none.
|
| // (We could use a slash from the base path in most cases, but not if
|
| // we remove the entire base path).
|
| String insert = "";
|
| +
|
| + /// Remove segments from the base path.
|
| + /// Start with the segment trailing the last slash,
|
| + /// then remove segments for each leading "../" segment
|
| + /// from the reference path, or as many of them as are available.
|
| while (baseEnd > baseStart) {
|
| baseEnd--;
|
| int char = baseUri.codeUnitAt(baseEnd);
|
| if (char == _SLASH) {
|
| insert = "/";
|
| - backCount--;
|
| if (backCount == 0) break;
|
| + backCount--;
|
| }
|
| }
|
| - // If the base URI has no scheme or authority (`_pathStart == 0`)
|
| - // and a relative path, and we reached the beginning of the path,
|
| - // we have a special case.
|
| - if (baseEnd == 0 && !base.hasAbsolutePath) {
|
| - // Non-RFC 3986 behavior when resolving a purely relative path on top of
|
| - // another relative path: Don't make the result absolute.
|
| +
|
| + if (baseEnd == baseStart && !base.hasScheme && !base.hasAbsolutePath) {
|
| + // If the base is *just* a relative path (no scheme or authority),
|
| + // then merging with another relative path doesn't follow the
|
| + // RFC-3986 behavior.
|
| + // Don't need to check `base.hasAuthority` since the base path is
|
| + // non-empty - if there is an authority, a non-empty path is absolute.
|
| +
|
| + // We reached the start of the base path, and want to stay relative,
|
| + // so don't insert a slash.
|
| insert = "";
|
| + // If we reached the start of the base path with more "../" left over
|
| + // in the reference path, include those segments in the result.
|
| + refStart -= backCount * 3;
|
| }
|
|
|
| var delta = baseEnd - refStart + insert.length;
|
|
|