lib.Uri: Fix __assemble(): No '://' for relative paths
Assembling a scheme-bearing form always writes '://' after the scheme, even if the input has no authority part. For a schemeless relative path such as '../../local/path', .full then becomes 'file://../../local/path', which re-parses with '..' as the host and '/../local/path' as the path, both entirely broken. Fix __assemble() to write a bare ':' instead of '://' when the input has no host and a relative path, so the assembled form re-parses back to the same relative path: full of '../../local/path' is now 'file:../../local/path'. Absolute paths and forms with an authority are unchanged. The assembled 'file:../../local/path' form is a valid URI under the RFC 3986 generic grammar (scheme with a rootless path), while RFC 8089's file URI ABNF admits only an empty or an absolute path. Uri thus trades RFC 8089 conformance for RFC 3986 compatibility: a relative path survives the full-and-reparse cycle unchanged. Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.84.2 Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
parent
23d3c596f6
commit
a1ae17c8cb
2 changed files with 23 additions and 1 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -21,6 +21,23 @@ assert '<hidden>' 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')
|
||||
|
|
|
|||
Loading…
Reference in a new issue