expressjs / serve-static

Serve static files
MIT License
1.38k stars 227 forks source link

Extensions vs Directory #138

Open betabong opened 3 years ago

betabong commented 3 years ago

When we have a directory named like a file, extensions should win over redirect. Let's assume this listing:

/news.html
/news/latest.html
/news/index.html

and we set the extensions options to ['html'].

Right now /news is redirected to /news/ and serves /news/index.html

But it should serve /news.html – only if that file is missing, it should redirect to the directory. Whereas /news/ should always go for the directory (index).

I achieved this by changing the sendFile method like follows, but there are probably better ways to achieve the same.

SendStream.prototype.sendFile = function sendFile (path) {
  var i = 0
  var self = this
  var onExtensionsFailed

  debug('stat "%s"', path)
  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()) {
      onExtensionsFailed = function() {
        self.redirect(path)
      }
      if (self._extensions.length > 0 && path[path.length - 1] !== sep) {
        return next()
      } else {
        return self.redirect(path)
      }
    }
    self.emit('file', path, stat)
    self.send(path, stat)
  })

  function next (err) {
    if (self._extensions.length <= i) {
      if (onExtensionsFailed) {
        return onExtensionsFailed()
      }
      return err
        ? self.onStatError(err)
        : self.error(404)
    }

    var p = path + '.' + self._extensions[i++]

    debug('stat "%s"', p)
    fs.stat(p, function (err, stat) {
      if (err) return next(err)
      if (stat.isDirectory()) return next()
      self.emit('file', p, stat)
      self.send(p, stat)
    })
  }
}

Does this make sense? (I am by the way trying to achieve the same kind of handling like Netlify does when serving static files).

ayyash commented 1 year ago

Yes I face the same issue when wanting to prerender

|--posts
|----posts1.html
|----posts2.html
|--posts.html

But I digress, the solutions are always there, either use index.html folders (gruesome), or in the next rule check the posts.html manually... or route the posts differently. But I guess it would have been a blessing for it to work out of the box with

{extensions: ['html'], redirect: false }