send icon indicating copy to clipboard operation
send copied to clipboard

Check extensions before performing directory redirects

Open dmgawel opened this issue 4 months ago • 2 comments

Problem

When using the extensions option, send inconsistently handles path resolution depending on whether a directory exists at the requested path.

For example, given this file structure:

dist/
  about.html
  about/
    team.html
  contact.html

When requesting paths with extensions: ['html'] configured:

  • /contact (no directory exists) → serves contact.html
  • /about (directory exists) → redirects to /about/ instead of serving about.html

This inconsistency occurs because:

  1. When a path doesn't exist, send receives an ENOENT error and tries extensions, successfully serving contact.html
  2. When a path exists as a directory, send immediately calls redirect(path) without trying extensions first
  3. The extension checking logic only runs when the initial stat() returns ENOENT

This behavior is problematic for static site generators and frameworks that want to serve files like about.html from the URL /about (no trailing slash) while also having subdirectories like about/team.html.

Solution

Modified sendFile() to attempt extension resolution before redirecting when:

  • The path resolves to a directory
  • Extensions are configured
  • The path has no file extension
  • The path doesn't end with a separator

The next() function now tracks whether the original path was a directory via an isDir parameter. If all configured extensions fail to resolve to a file and the original path was a directory, it falls back to the standard directory redirect behavior.

This ensures consistent behavior:

  • /contact with contact.html present → serves contact.html
  • /about with about.html present → serves about.html
  • /about with only about/ directory → redirects to /about/
  • /about with both present → serves about.html (prioritizes file over directory)

References

Resolves https://github.com/pillarjs/send/issues/194 Related to https://github.com/expressjs/serve-static/issues/138

dmgawel avatar Oct 01 '25 08:10 dmgawel