Skip to content

fix: keep the authority when encoding a UNC path as a file URI - #530

Open
metif12 wants to merge 1 commit into
vlang:masterfrom
metif12:fix/path-to-uri-unc-authority
Open

metif12 wants to merge 1 commit into
vlang:masterfrom
metif12:fix/path-to-uri-unc-authority

Conversation

@metif12

@metif12 metif12 commented Oct 3, 2026

Copy link
Copy Markdown

Problem

uri_to_path resolves a file://host/... URI to a //host/share/... UNC path
correctly, and there is already a test for it:

assert uri_to_path('file://server/share/main.v') == '//server/share/main.v'

path_to_uri did not invert that. It treated the resulting UNC path as an
ordinary absolute path and emitted four slashes:

client sends   : file://server/share/proj/main.v
uri_to_path    : //server/share/proj/main.v
path_to_uri    : file:////server/share/proj/main.v

The host ends up in the path component instead of the authority. Per RFC 8089 a
UNC path's host belongs in the authority — file://server/share/proj/main.v —
and file:////server/share/... is not a valid file URI for it.

The round trip breaking is the part that actually bites. VLS keys open buffers,
the index, and every published diagnostic and code lens by URI, so the URI it
derives for a file on a network share never matches the URI the editor sent for
that same file. Reproduced directly:

client uri    : file://server/share/proj/main.v
resolved path : //server/share/proj/main.v
vls re-encodes: file:////server/share/proj/main.v
same key      : false

This is a Windows-only path: \\server\share\... has no POSIX equivalent that VLS
meets in practice.

Fix

Encode the host as the authority:

if normalized.starts_with('//') {
	return 'file:' + percent_encode_path(normalized)
}

placed after os.to_slash and before the drive-letter branch, so a single-slash
absolute path and a Windows drive path still take exactly the path they did
before. This is symmetric with what uri_to_path already does with a non-local
authority, so the pair now round-trips.

Test

test_path_to_uri_keeps_the_authority_of_a_unc_path covers the round trip from
the client's URI, asserts the result is not file:////, checks that a share
containing a space is still percent-encoded and still round-trips, and pins
POSIX and drive-letter paths so the change cannot silently widen. There was no
path_to_uri coverage for a UNC path before.

Validation

V 0137eb5 (the vlang/v revision CI builds from), Windows.

interop_test.v on this branch: OK.

For the regression check I applied the same two-file change on top of
#526 +
#527 +
#528 +
#529, which are green together on
master's current state, and ran the whole suite:

OK    compilation_test.v     OK    index_test.v      OK    interop_test.v
OK    integration_test.v     OK    handlers_test.v   OK    lsp_test.v
Summary for all V _test.v files: 6 passed, 6 total.

v fmt -verify . also exits 0. URI keys are used pervasively — app.open_files,
the index, diagnostics, code lens, workspace edits — so this was worth checking
against the full suite rather than only the new test.

Note on the diff

As with #529, this branch runs v fmt over the two files it touches, since
master is not v fmt-clean (#528).

`uri_to_path` already resolves a `file://host/...` URI to a `//host/share/...`
UNC path, but `path_to_uri` then treated that as an ordinary absolute path and
emitted four slashes:

    client sends   file://server/share/proj/main.v
    uri_to_path    //server/share/proj/main.v
    path_to_uri    file:////server/share/proj/main.v

The share ends up in the path instead of the authority. That is not a valid
file URI (RFC 8089 puts the host in the authority), and it breaks the round
trip in a way that matters: VLS keys open buffers, the index, and every
published diagnostic and code lens by URI, so the URI it derives for a file on
a network share never matches the one the client sent for the same file.

Encode the host as the authority instead:

    path_to_uri('//server/share/proj/main.v') == 'file://server/share/proj/main.v'

Percent-encoding of the path component is unchanged, so a share with a space
still encodes correctly and still round-trips. Single-slash absolute paths and
Windows drive paths are untouched, so POSIX and local Windows behaviour is
identical.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant