Skip to content

Relative File URIs and RFC 3986 (dart:io, dart:core) #60639

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
RohitSaily opened this issue Apr 29, 2025 · 4 comments
Closed

Relative File URIs and RFC 3986 (dart:io, dart:core) #60639

RohitSaily opened this issue Apr 29, 2025 · 4 comments
Assignees
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-core type-enhancement A request for a change that isn't a bug

Comments

@RohitSaily
Copy link
Contributor

RohitSaily commented Apr 29, 2025

Dart SDK version: 3.9.0-63.0.dev (dev) (Sun Apr 27 17:07:04 2025 -0700) on "macos_x64"

This is a discussion to determine if additional API would be beneficial and not a request to change current behaviour of current API since it is not a matter of correctness, so such changes would be non-necessarily breaking.

Current dart:io and dart:core API

The default behaviour which is documented for file system objects of dart:io and the URI API of dart:core is to treat relative paths as its own thing and not a URI with a scheme. For example

print(Uri.file('.').hasScheme);

outputs

false

and

print(Directory('.').uri.scheme);

outputs nothing because there is no scheme.

Relative File URIs

RFC 3986 defines the URI grammar as

The generic URI syntax consists of a hierarchical sequence of
components referred to as the scheme, authority, path, query, and
fragment.

URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty

Applying grammar productions using path-rootless, it is possible to derive File URIs of the form

"file:" path-rootless [ "?" query ] [ "#" fragment ]

Which is relative paths, optionally with queries and fragments eg file:Documentation/readme.md#getting-started.

RFC 3986 Compliance

The Dart behaviour deviates from RFC 3986, which is fine as its behaviour is documented and still practical. Since RFC 3986 is a widely adopted specification, should additional API be introduced that conforms to it as expected. Something like

Directory.rfc('.')

will have a URI file:. and

Uri.fileRfc('.')

will also have URI file:..

This would also mean, for this new API,? can be treated as a query declaration and # can be treated as the fragment declaration.

@lrhn
Copy link
Member

lrhn commented May 1, 2025

File URIs are goverened by RFC 8089. The grammar for them is:

      file-URI       = file-scheme ":" file-hier-part

      file-scheme    = "file"

      file-hier-part = ( "//" auth-path )
                     / local-path

      auth-path      = [ file-auth ] path-absolute

      local-path     = path-absolute

      file-auth      = "localhost"
                     / host

Notice that all paths are path-absolute, so a file: URI cannot be relative and have a scheme.

(We generally also enforce that all file: URIs have an authority, even if it's empty, so the minimal file: URI is file:///. I no longer remember the source of that decision.)

To make this work with relative paths, we have the Uri.file constructor recognize a relative path, and create a relative URI Reference from it, rather than a URI. That is what allows Uri.file('/foo/bar/baz').resolveUri(Uri.file('../qux')) to work and yield file:///foo/qux.

In general, the Dart Uri class can represent both URIs and URI references.

I don't expect that we will want to change this behavior, since it may break existing code.

@lrhn lrhn self-assigned this May 1, 2025
@lrhn lrhn added area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-core type-enhancement A request for a change that isn't a bug labels May 1, 2025
@RohitSaily
Copy link
Contributor Author

I was not aware of the concept of URI references, the way things are currently implemented makes sense. Maybe all that's needed is one method that fully resolves/normalizes a relative file URI reference to the newer RFC 3986 format?

@lrhn
Copy link
Member

lrhn commented May 5, 2025

I don't think we will make any changes here.

The RFC 3986 format is not newer than the RFC 8089 file: URI rules.

A format of file:unrooted/path is not a relative path. It's an absolute URI with no authority part and a path part that doesn't start with /. That's still an absolute URI, RFC 3986 makes no interpretation of what it means for a path to not start with /.

If you try to resolve that URI against another URI, like file://example.com/path, the result will be file:unrooted/path (according to the URI resolution algorithm).

If we start interpreting it as a file path, we should go full RFC 8089, and then it should be normalized to file:///unrooted/path anyway.

@RohitSaily
Copy link
Contributor Author

Yes you are correct that 8089 is newer, I seemed to have confused myself. I suppose it is better off as it currently is since it clearly distinguishes what is intended to be relative and absolute and leaves the interpretation up to the developer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-core type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

2 participants