-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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.