-
-
Notifications
You must be signed in to change notification settings - Fork 19.7k
Description
Hello everyone!
I just ran into a bug in res.download
which is also an inconsistency between res.download
and res.sendFile
.
The bug
res.download
breaks for relative paths when specifying a root in the options argument. Express tries to access the following path: {options.root}/{process.cwd()}/{path}
. Expected is {options.root}/{path}
Example
In the example below I try to access the file /dev/null
. The following Error is raised when navigating to /download
Error: ENOENT: no such file or directory, stat '/dev/home/user/my-project/null'
const express = require('express')
const app = express()
.get('/', (req, res) => {
res.send(`
<ul>
<li><a href="/sendFile">res.sendFile</a></li>
<li><a href="/download">res.download</a></li>
</ul>
`)
})
.get('/sendFile', (req, res) => {
res.sendFile('null', { root: '/dev' })
})
.get('/download', (req, res) => {
res.download('null', 'null', { root: '/dev' })
})
.listen(() => {
console.log(`Listening on http://localhost:${app.address().port}`)
})
res.sendFile
works as expected.
Expectation
My assumption that res.download
should behave like res.sendFile
is based on the following line of the documentation
The optional options argument passes through to the underlying res.sendFile() call, and takes the exact same parameters.
Cause
Problematic is the following line in res.download: /lib/response.js:575:
// Resolve the full path for sendFile
var fullPath = resolve(path);
The resolve method is imported from the 'path' module: https://nodejs.org/api/path.html#pathresolvepaths This is where the current working directory gets added. Anyway res.sendFile
won't allow relative paths at all without a root specified. So I suggest to leave out the path.resolve
call at all for a breaking release. For a non breaking fix one could only call path.resolve
if root is not set in options.
Research
I have only looked briefly but have not found this fixed in the 5.x branch.