Resolve reference
as an URI relative to this
.
Returns the resolved URI.
The algorithm "Transform Reference" for resolving a reference is described in RFC-3986 Section 5.
Updated to handle the case where the base URI is just a relative path - that is: when it has no scheme or authority and the path does not start with a slash. In that case, the paths are combined without removing leading "..", and an empty path is not converted to "/".
Source
Uri resolveUri(Uri reference) {
// From RFC 3986.
String targetScheme;
String targetUserInfo = "";
String targetHost;
int targetPort;
String targetPath;
String targetQuery;
if (reference.scheme.isNotEmpty) {
targetScheme = reference.scheme;
if (reference.hasAuthority) {
targetUserInfo = reference.userInfo;
targetHost = reference.host;
targetPort = reference.hasPort ? reference.port : null;
}
targetPath = _removeDotSegments(reference.path);
if (reference.hasQuery) {
targetQuery = reference.query;
}
} else {
targetScheme = this.scheme;
if (reference.hasAuthority) {
targetUserInfo = reference.userInfo;
targetHost = reference.host;
targetPort = _makePort(reference.hasPort ? reference.port : null,
targetScheme);
targetPath = _removeDotSegments(reference.path);
if (reference.hasQuery) targetQuery = reference.query;
} else {
targetUserInfo = this._userInfo;
targetHost = this._host;
targetPort = this._port;
if (reference.path == "") {
targetPath = this._path;
if (reference.hasQuery) {
targetQuery = reference.query;
} else {
targetQuery = this._query;
}
} else {
if (reference.hasAbsolutePath) {
targetPath = _removeDotSegments(reference.path);
} else {
// This is the RFC 3986 behavior for merging.
if (this.hasEmptyPath) {
if (!this.hasScheme && !this.hasAuthority) {
// Keep the path relative if no scheme or authority.
targetPath = reference.path;
} else {
// Add path normalization on top of RFC algorithm.
targetPath = _removeDotSegments("/" + reference.path);
}
} else {
var mergedPath = _mergePaths(this._path, reference.path);
if (this.hasScheme || this.hasAuthority || this.hasAbsolutePath) {
targetPath = _removeDotSegments(mergedPath);
} else {
// Non-RFC 3986 beavior. If both base and reference are relative
// path, allow the merged path to start with "..".
// The RFC only specifies the case where the base has a scheme.
targetPath = _normalizeRelativePath(mergedPath);
}
}
}
if (reference.hasQuery) targetQuery = reference.query;
}
}
}
String fragment = reference.hasFragment ? reference.fragment : null;
return new Uri._internal(targetScheme,
targetUserInfo,
targetHost,
targetPort,
targetPath,
targetQuery,
fragment);
}