[Bug] Foundation URL should support UNC path

Hi everyone,
I am currently playing around with the dev snapshots under windows (kudos @compnerd), and I noticed that Foundation.URL does not seem to like UNC paths. But I'm not sure where the error comes from because I haven't got LLDB running in VSCode on Windows yet, but it seems that standardizingPath is the cause.
Anyway, I can work around the problem with:

#if os(Windows)
let rawData: Data
if url.path.contains(":") {
  rawData = try Data(contentsOf: url)
} else { // UNC network path
  rawData = NSData(contentsOfFile: "/" + url.path)! as Data
}
#else
let rawData = try Data(contentsOf: url)
#endif

I have seen that @gmittertreiner has written the implementation, maybe she can help me find and fix the bug in Foundation.

1 Like

Hi @Daniel_Mullenborn,

Do you have an example UNC path that can reproduce the issue? This sounds like we don't have enough test coverage, so the example here would allow us to expand the test coverage and fix the issue.

Saleem

import Foundation

let path = #"\\jasmine\Pool\Daniel\SPC\Al_Abdaliyah_2012.mto"#
let url = URL(fileURLWithPath: path)
var rawData = try? Data(contentsOf: url)
dump(rawData) // nil
rawData = NSData(contentsOfFile: "/" + url.path)! as Data 
dump(rawData) // Data

With the file path in code snippet I encountered the problem.

Just looking at what you've posted, I would say that the issue is with Data(contentsOf:) not supporting UNC paths; it's not URL's fault.

Out of interest, what does URL(fileURLWithPath:) return in your example? I reckon it should return file:////jasmine/Pool/Daniel/SPC/Al_Abdaliyah_2012.mto (4 slashes - 2 for the hostname start, 1 for the hostname end, and 1 for the leading empty component of the UNC path).

EDIT: I think it should be 4 slashes. I Googled it and some people say it should be 5 for some reason.

It took me a while to figure out what's going on here. I believe you are trying to detect a Windows drive letter (e.g. "C:"), but there are a couple of things to note about that:

  • Windows drive letters can sometimes be represented as C| in URLs instead of C:. Browsers do accept both (check out the result - even on macOS Safari, the C| has correctly been turned in to a C: because that's the "normalised" way to write a Windows drive letter).
  • It's also important to check that this is a file: URL.
  • Windows drive letters can only be a single ASCII alpha, and they must be the first path component. For example, 9: is not a Windows drive letter, nor do /hello/:world:/ or /test/C:/foo contain any Windows drive letters.

I understand that you're just illustrating the problem, but if you do submit a patch, be sure to consider those things :nerd_face:

I thought the point of a UNC path was that the first component was a host name. So, file://jasmine/foo/bar.

Right, but the point of UNC (as I understand it) is to encode the hostname as part of the path. They are paths, it’s just that the OS handles them in a special way.

Going from path -> URL -> path should preserve the leading empty component which tells the OS to interpret it specially.

EDIT: Ah yes I remember reading about this a while ago:

There are two ways that Windows UNC filenames (such as \\server\folder\data.xml ) can be represented. These are both described in [5] as "non-standard". The first way (called here the 2-slash format) is to represent the server name using the Authority part of the URI, which then becomes file://server/folder/data.xml . The second way (called here the 4-slash format) is to represent the server name as part of the Path component, so the URI becomes file:////server/folder/data.xml . Both forms are actively used. Microsoft .NET (for example, the method new Uri(path) ) generally uses the 2-slash form; Java (for example, the method new URI(path) ) generally uses the 4-slash form. Either form allows the most common operations on URIs (resolving relative URIs, and dereferencing to obtain a connection to the remote file) to be used successfully. However, because these URIs are non-standard, some less common operations fail: an example is the normalize operation (defined in RFC 3986 and implemented in the Java java.net.URI.normalize() method) which reduces file:////server/folder/data.xml to the unusable form file:/server/folder/data.xml .

Wikipedia

It's worth noting that the referenced RFC does not match what modern browsers do. They all kind of disagree with each other, and there are efforts from Apple/Google/Mozilla/etc to try and unify them around a new standard.

4 Likes