expressjs.com
expressjs.com copied to clipboard
static-files.md (Case sensitivity of path)
Hi,
I encountered a case that when serving files with MacOS as host for express.static, it will fail to find the file if the path requested is of a different case as the file. I look debugged into the code and discovered that express.static
is actually using the npm package serve-static
and serve-static
uses the npm package send to return the file.
And send actually uses Node.js's fs.stat
to check that the file exists before returning the file. And the case sensitivity of that call depends on the host OS of Express.js. For host OSes that are case sensitive the call will return an error of the file not being found.
fs.stat(path, function onstat (err, stat) {
if (err && err.code === 'ENOENT' && !extname(path) && path[path.length - 1] !== sep) {
// not found, check extensions
return next(err)
}
if (err) return self.onStatError(err)
if (stat.isDirectory()) return self.redirect(path)
self.emit('file', path, stat)
self.send(path, stat)
})
Would it be a good idea to add a note that this middleware could be case-sensitive depending on the host of Express? Since it could cause behaviors that are not easily traceable if the developer most an application built on a case insensitive OS and deployed it on a case sensitive OS
Hey @seetd, I am fine adding a comment to this effect. PR's welcome!
Hi @wesleytodd ,
Thanks I will look into adding in the comment.
Hi @wesleytodd,
As an update I am still working on this. I had to switch to a new Mac so it took sometime to get everything up again. PR should be coming soon
@dougwilson Sorry for not understanding the structure of the project. Should I add the note to the Readme in https://github.com/expressjs/serve-static for this?
It depends on where exactly you're looking to put it on the website. If you want to put it in that exact location, then it would need to be incorporated into that module's readme. If you wanted to put it in express.static docs, then no.
But that brings up a good point: perhaps we should come up with some wording we want to use here and where it should go in the docs? For example I assume that would also apply to res.sendFile API as well.
Another thought is that perhaps it should not mention a specific OS / file system, unless the intention is that you're going to enumerate all of them. It can perhaps just say to reference your OS documentation to determine if it is case-sensitive or something generic like that? Maybe even just reference Node.js documentation on the subject (i.e. the same issue would occur with Node.js fs.readFile
, which is basically the underlying mechanism under all of this), as maybe they have some good docs on how their fs
module handles this.
Thanks for the quick response and pointing out that the case-sensitivity behavior impacts more than serve-static. I just followed the chain of code in response.sendFile
, I might need to debug it to be confirm it but it appears that it uses the same send
module as serve-static
. I also checked how Node.js handles this in their fs
documentation and it appears that it does not detail this behavior as well. I do find a guide Working with Different Filesystems in the NodeJs documentation site, that describes how to handle filesystem differences when coding in Nodejs.
Since this impacts multiple modules in Express, I would like to propose a new page under the Advance Topics with the title along the lines ofWorking with Different Filesystems
(en/advanced/working-with-different-filesystems.md). The article will enumerate the parts of Express that is impacted by this behavior and also reference the Node.js guide for anyone who wants to find out in detail.
Just for some context on why I filed this issue, I discovered this behavior when working on some code that had different casing for filenames. And based on the communication on that project flagChain test failing on MacOS on PWA Training Labs by Google Developer Training I think some developers (me included) thought that Express was case-insensitive. That actually took me many hours to figure out what the error was. So I thought some form of documentation on this might help others down the road.
Thanks