-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
fs: allow file: URL strings as paths for fs.promises #20950
Conversation
return path; | ||
path = new URL(path); | ||
} else if (path == null || !path[searchParams] || | ||
!path[searchParams][searchParams]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs re-aligning
!path[searchParams][searchParams]) { | ||
return path; | ||
} | ||
if (path.protocol !== 'file:') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we can avoid this check for the first case where we already know it starts with 'file://'
?
@@ -1392,6 +1392,20 @@ function getPathFromURLPosix(url) { | |||
return decodeURIComponent(pathname); | |||
} | |||
|
|||
function getPathFromURLString(path) { | |||
if (typeof path === 'string') { | |||
if (!path.startsWith('file://')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A possible micro-optimization here would be to make this path.length < 7 || !path.startsWith('file://')
.
Also, is it intentional to be enforcing a lowercase protocol like that?
@@ -3381,6 +3381,9 @@ The `fs.promises` API provides an alternative set of asynchronous file system | |||
methods that return `Promise` objects rather than using callbacks. The | |||
API is accessible via `require('fs').promises`. | |||
|
|||
In addition to returning a promise, `file:///` URL strings are also permitted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One extra /
on this line.
Is the idea that this will eventually make its way into the non-promise based API too? |
@jdalton that could be nice but I'm not sure what the process is here in terms of managing the small security risk. From my perspective that could well make sense for a major release that is able to relax such a constraint. |
Yap. Make the potential breaking change in the non-promises variants the next major. |
Generally +1 on this but the docs should point out the fact that proper validation of file URL paths can occur only after the URL is parsed... which means userland code that wants to perform it's own validation will still need to create the |
Should we add a doc warning for absolute paths in general or |
Heh, tbh it's not a bad idea |
hmmm... just a quick data point... I posted about the possibility of us doing this on Twitter and the immediate reaction from a few folks was literally "Please don't." |
I'm on the Please Don't front, but I'm happy to expand on it: Changing the validation requirements of arguments between the callback and promise based APIs feels very risky to me. It encourages folks to introduce substantial risk when porting their code from one to the other. As a user, I would expect the promise version to just be what Because of the expectation that promise and callback APIs are different interfaces to the same thing, I am, as a rule, -1 on any change to the arguments passed to a promise-based API that are not also made to a callback-based API. To back up a little, do I understand correctly that there are two justifications for this change?
I don't find either of these very convincing. The sugar added to |
Please don't do this. (In fact, can we roll back passing I maintain a lot of fs utils that get quite a bit of usage. (Among them: rimraf, glob, tar, which, graceful-fs, isexe, and quite a few others.) That's where I've done most of my OSS work. One of the largest sources of bugs working with file systems is the fact that Windows and Posix have very different ways of expressing the same things. I understand that it's nice to be able to do things like Let's let the long awful history of And I'd also argue that we should let the even longer and even more awful history of Windows file system paths be a lesson to us that having multiple different ways to encode and express the same concept is almost always a terrible idea. If we do this, then all of the logic that I've got kicking around that detects whether a path is absolute has to change. These discrepancies around file system handling are not mere inconveniences (though they are really annoying inconveniences). They also create security problems by increasing the attack surface for vulnerabilities. When string handling logic is more complicated than necessary, bugs creep in, and those bugs allow attackers to pwn machines. (Seriously, look through the NSP advisories and observe how many of them boil down to "parsed a string wrong".) We don't need Do not multiply entities unnecessarily. |
Not seeing any reason to revert the support for the URL object as that has been there for a while now without any issues. But, I think the push back here is enough to say that we should hold back on enabling the URL strings. |
The security concerns do sound like they outweigh the usability here unfortunately. Strings are hard! As these universal modules workflows are explored it is important to be able to clearly understand what constraints we have to provide the best user experience for modules so a negative result on this one is still useful information. I also had a look at a common That said, the universal usability problems still apply -
So we really don't want users doing This all seems to indicate that Thanks all for feedback. |
Also worth noting the full expanded conversion is actually closer to: fs.readFile(decode(new URL(import.meta.url).pathname.substr(isWindows ? 1 : 0))) |
I suspect that could be because it's not getting much use? I haven't seen any issues or PRs looking for support for this feature in the userland modules I maintain. It's marked as experimental, and hasn't gotten a ton of advocacy or discussion, from what I've seen. What about adding a
I'm not really seeing that? I'm making an assumption that that's the impetus for this, simply because I don't know where else file:// URLs are going to show up in day to day node usage. Most users never touch the module system internals, they just use |
Aside from my fantasies: yes, it would be so nice if either we'd just insisted from the get-go that Windows users get comfortable with UNC paths and never added support for But the time to have the first discussion was 2010, and the second was 2009, so we're a bit late. I don't see how we get there without rewriting a lot of userland code, and/or going through a very long and brutal period of usability and security issues. |
As a follow-on to the security issue raised in #20944, this allows support for
file://
URL strings in thefs.promises
API only.In #17658 it was noted that files or directories can exist with the name
file:
leading to worries over ambiguity here. For this reason, this implementation only supports the exact prefix"file://"
in File URLs so that a rare file or directory called 'file:/', can still be reliable and uniquely distinguished from file URLs.The URL standard actually suggests using strings over the object where possible in https://url.spec.whatwg.org/#url-apis-elsewhere, so it would be good to be able to enable such a best-practice.
This will also enable use cases like
fs.readFile(import.meta.url)
for modules, where the URL is provided as a string.Performance is largely unaffected as there is a fast opt-out of this code path through the string prefix check.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes