diff --git a/src/python/jw/pkg/lib/Uri.py b/src/python/jw/pkg/lib/Uri.py index cada582e..51534410 100644 --- a/src/python/jw/pkg/lib/Uri.py +++ b/src/python/jw/pkg/lib/Uri.py @@ -18,7 +18,12 @@ class Uri: if self.__p.path.startswith('~'): return self.path if scheme: - ret += f'{self.protocol}://' + if self.hostname is None and not self.path.startswith('/'): + # -- No authority and a relative path: '://' would + # re-parse the first path segment as a host + ret += f'{self.protocol}:' + else: + ret += f'{self.protocol}://' if credentials and self.username: ret += self.username if self.password: @@ -156,6 +161,12 @@ class Uri: ret.__password = None if not path: return ret + if ret.__string.endswith('://'): + # -- Empty authority: the trailing '/' is part of the '://' + # separator, so a leading slash in path must be kept to stay + # an absolute path + ret.__string += path if path.startswith('/') else '/' + path + return ret if ret.__string[-1] == '/': if path[0] == '/': ret.__string += path[1:] diff --git a/test/unit/python/jw/pkg/lib/Uri/test.py b/test/unit/python/jw/pkg/lib/Uri/test.py index a435b8b2..dc68b84f 100644 --- a/test/unit/python/jw/pkg/lib/Uri/test.py +++ b/test/unit/python/jw/pkg/lib/Uri/test.py @@ -21,6 +21,23 @@ assert '' in u.safe_full_with_username # safe version hides password u = Uri('/local/path') assert u.scheme == 'file' assert u.protocol == 'file' +assert u.full == 'file:///local/path' + +# Relative paths default to file, too +u = Uri('../../local/path') +assert u.scheme == 'file' +assert u.protocol == 'file' +assert u.path == '../../local/path' + +# full keeps relative paths relative: '://' would re-parse the +# first segment as a host +assert u.full == 'file:../../local/path' +assert Uri(u.full).path == '../../local/path' + +# An explicit file: scheme with a relative path round-trips, too +u = Uri('file:../../local/path') +assert u.path == '../../local/path' +assert u.full == 'file:../../local/path' # Pimp returns existing Uri unchanged u1 = Uri('ssh://host/path')