runtime: [Uri] Does not allow $ in a hostname

Issue Title

System.Uri cannot parse trailing $ sign in paths

General

We want to store and load data from WSL2 rootfs projection, which is exposed into Windows as “\\wsl$”, we use this UNC path internally, to construct and manipulate the path. However, System.Uri cannot parse “\\wsl$” and throws a format exception:

System.UriFormatException: ‘Invalid URI: The hostname could not be parsed.’

Example code and repro

var uri = new System.Uri(@"\\wsl$");

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 35 (31 by maintainers)

Most upvoted comments

Thanks @karelz. I have met with the WSL team, they are open to changing the share name to work with System.Uri, they have a candidate for a new name, and are working on telemetry to validate that the new name does not conflict with other names. I will provide more updates here once I have them.

Based on offline discussion, WSL team is considering change of the name (as it violates spec). Closing for now, we can reopen and reconsider if things change in future.

I am against this.

I am too 😄

Oh looks like as of Windows 10 20175 they added support for \\wsl\ instead of \\wsl$\ with the dollar sign version being a legacy fallback. https://docs.microsoft.com/en-us/windows/wsl/release-notes

This build should be getting generally released soon enough. (Edited: I thought this was coming in 21H1, I was wrong. Probably 21H2?)

As noted offline, before going to far we probably want to understand whether this would help @itodirel anyway, given any change would almost surely only be in .NET Core. (He mentioned Visual Studio which still runs on .NET Framework.)

@itodirel do you have an update to share? I will unlock meantime.😀

@zivkan share names with $ are working correctly to our best knowledge. The name in question here is hostname where it is technically not allowed per spec, although wsl$ uses it that way.

Oops, sorry. Yes, I was totally mixed up.

We’ve discussed this in triage:

  • UNC spec requires the host to be a FQDN. As $ is not a valid character for DNS hostnames, a path like \\wsl$ technically violates the spec. We should seek guidance from the spec’s maintainers regarding this.
  • RFC 3986 allows such hostnames under the reg-name syntax definition, it is System.Uri that chooses to use a more-strict DNS validation for hostnames.
  • We are willing to relax this restriction for UNC paths only (both in implicit \\wsl$ and explicit file:////wsl$ form). We don’t see an upside to allowing it for other schemes (such as http).

Also, new Uri(“\share$”, UriKind.Relative) kind of works

Yes, but relative is more of a Uri string wrapper that doesn’t provide much utility.

Also worth noting that \\wsl$ is not a valid URI at all

It’s not valid because of the $ being in the host - System.Uri supports implicit file as input, so \\wsl\foo without the explicit file scheme is fine.

If you don’t think about it being in an implicit file form though, the format itself is not against the Uri spec - it’s just a question of what kind of hostname rules are used. See https://github.com/dotnet/runtime/issues/36595#issuecomment-630066238

Or even a fancier (and far more dangerous API): Uri.MakeThisArbitraryStringIntoAUriPlease(string randomString)

I am against this. UriKind.Relative is kind-of this already - a string wrapper with no utility. If a string can’t be parsed and understood by Uri, it can’t provide info with properties either.

If we decide this is something we would like to support, the question of allowing $ in the host opens up discussion for whether we should support Registry-based Naming Authority in its entirety (that would include more characters and percent-encoding) or just make an exception for $.

I am confused. I understood the original report as ‘\wsl$’ is a hostname. (likely a fake one like localhost, but a hostname) Did I misunderstand?

new Uri("\\wsl$") parses as an absolute URI, so it interprets the wsl$ as a hostname.

new Uri("\\wsl$", UriKind.Relative) parses as a relative, so it interprets the wsl$ as part of the path/query.

I’m not going to speak for @itodirel, but I’ve built systems in the past that used URIs to specify actions.

  • HTTP/HTTPS schemes were to launch browser tabs with the URI.
  • FILE scheme was used to open files
  • Other application specific schemes (like CMD, SESSION, etc.) were also used.

Relative URIs were also used to add/override parameters.

It won’t be becuase . alone is not a valid host either.

$ itself in the path is not problematic - for example \\foo\C$ works fine.

This is an issue with that part of a UNC path being the host - $ in the host name will not be recognized.

The validation fails in IsValidDomainLabelCharacter for http Uris or UncNameHelper.IsValid for UNC paths.

This stems from the fact that System.Uri validates hostnames as a Server-based Naming Authority for DNS resolution and not by the less-strict, generic Registry-based Naming Authority rules as defined in RFC 2396 and 3986.