[whatwg/url] Resolving relative `file:` URL strings without explicit base into URL objects (Issue #879)

LiviaMedeiros created an issue (whatwg/url#879)

### What is the issue with the URL Standard?

## To put it shortly

`new URL('file:a/b')`, `new URL('file:./a/b')`, `new URL('file:../a/b')` should be `URL` objects with absolute URLs resolved using current context.
Currently, the spec considers it to have [`special-scheme-missing-following-solidus`](https://url.spec.whatwg.org/#special-scheme-missing-following-solidus) validation error and implicitly resolves it against `/`.

## Problem

According to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986.html) and [RFC 8089](https://www.rfc-editor.org/rfc/rfc8089.html), a `file:` URI that doesn't start with `/` or `//` must be treated as relative-path reference. In the context of these RFCs, it's meaningful only in relative resolution algorithms, paired with the base URI (absolute).
When base URI is explicitly provided, ``new URL(`file:${relativePath}`, base)`` is same as ``new URL(relativePath, base)``.
However, when base is not provided, it seems that neither RFCs nor WHATWG URL spec explicitly defines what to do. This leads to unexpected (and I think, undesired) implementation-specific results.

## What implementations do

`new URL('file:a/b')`
Firefox (v142.0.1):
```js
host: ""
href: "file:///a/b"
origin: "null"
pathname: "/a/b"
```
Chrome (v140.0.7339.80):
```js
host: "a"
href: "file://a/b"
origin: "file://"
pathname: "/b"

// but new URL('file:./a/b')
host: "."
href: "file://./a/b"
origin: "file://"
pathname: "/a/b"
```
Node.js (v24.7.0):
```js
host: "",
href: "file:///a/b",
origin: "null",
pathname: "/a/b",
```

## Why relative `file:` URL matters

Relative filepaths are used everywhere. Relative URL with `file:` schema is a clear, unambiguous way to refer to a file in similar way. There are at least two use cases for them:
1. (Potentially standartized one day) `fetch('file:...')`. `fetch` expects URL object or urlstring, and relative urlstrings would be very useful. Resolving them against root is a footgun.
1. There were multiple occasions where people wanted `node:fs` functions to accept urlstrings (detected if starting with `file:`) along with path strings and URL objects, or to allow `node file:///path/to/file.js`. This can not be implemented directly (because it's ambiguous when path strings are accepted) but the demand exists, and so do userland implementations.

In the latest versions of Node.js, `node --entry-url file:relative/path/to/file.js?canHave=searchParams#andHashString` is already resolved against CWD.

I'm not aware of any use cases for relative `file:` URLs intentionally being resolved against root.

## Proposal

I think, the WHATWG URL objects built from relative references should be defined as result of relative resolution, using current context as base URI.

In browsers, `new URL('file:relativePath')` must be equal to `new URL('file:relativePath', document.location.href)`.
In non-browsers, `new URL('file:relativePath')` must be equal to `new URL('file:relativePath', cwdURL)`, where `cwdURL` is an absolute `file:` URL pointing to current working directory with trailing slash (example: cwdPath `/home/livia` translates to cwdURL `file:///home/livia/`).

In browsers, this would be aligned with the resolutions in HTML. `<a href="file:a/b">` points to `a/b` relative to current location.
In non-browsers, this would be aligned with the resolution in path strings. `node:path.resolve("a/b")` resolves against CWD, and in most cases relative paths are resolved against it implicitly.

## Additional info

The spec should provide example(s) with `file:` URI without leading slashes and explicitly state that these are relative paths (not absolute with implicit root, and not auth-path with host).

Unless I'm missing some edge cases, parsing *any* `file:` URL can be done using the relative resolution algorithm, since in case of absolute URL the base would be ignored anyway.
Maybe the actual implementations should have fast-path when the URL is absolute, but in the spec the patch might be straightforward. In the [4.4. URL parsing](https://url.spec.whatwg.org/#url-parsing):
1. When we enter [file state](https://url.spec.whatwg.org/#file-state), if `base` is null, set `base` to the *[bikeshedded term for the "current context" URI]*
1. Add definition of current context, which in browsers should be URL of the document and in non-browsers should be CWD.
1. (Optional) If for whatever implementation-and-platform-specific reason current context can not be used, the spec can explicitly define `file:///` as fallback value instead of null.
1. (Optional) In [scheme state](https://url.spec.whatwg.org/#scheme-state) step 2-5, remove the "If [remaining](https://url.spec.whatwg.org/#remaining) does not start with "//", [special-scheme-missing-following-solidus](https://url.spec.whatwg.org/#special-scheme-missing-following-solidus) [validation error](https://url.spec.whatwg.org/#validation-error)." step. Per RFCs relative path without `//` is valid.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/url/issues/879
You are receiving this because you are subscribed to this thread.

Message ID: <whatwg/url/issues/879@github.com>

Received on Thursday, 11 September 2025 19:47:45 UTC