Skip to content

Commit

Permalink
fix: file not found errors when the root has a trailing slash (#436)
Browse files Browse the repository at this point in the history
* fix not found

* fix not found

* fix not found

* fix not found

* revert change left out from the other rbanch

* revert change left out from the other rbanch

* test

* use one handler for GET and HEAD
  • Loading branch information
gurgunday committed Feb 7, 2024
1 parent cd85aca commit 6c66465
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 16 deletions.
28 changes: 12 additions & 16 deletions index.js
Expand Up @@ -13,7 +13,6 @@ const contentDisposition = require('content-disposition')
const dirList = require('./lib/dirList')

const endForwardSlashRegex = /\/$/u
const doubleForwardSlashRegex = /\/\//gu
const asteriskRegex = /\*/gu

const supportedEncodings = ['br', 'gzip', 'deflate']
Expand Down Expand Up @@ -112,33 +111,30 @@ async function fastifyStatic (fastify, opts) {
throw new Error('"wildcard" option must be a boolean')
}
if (opts.wildcard === undefined || opts.wildcard === true) {
fastify.head(prefix + '*', routeOpts, function (req, reply) {
pumpSendToReply(req, reply, '/' + req.params['*'], sendOptions.root)
})
fastify.get(prefix + '*', routeOpts, function (req, reply) {
fastify.get(prefix + '*', { ...routeOpts, exposeHeadRoute: true }, (req, reply) => {
pumpSendToReply(req, reply, '/' + req.params['*'], sendOptions.root)
})
if (opts.redirect === true && prefix !== opts.prefix) {
fastify.get(opts.prefix, routeOpts, function (req, reply) {
fastify.get(opts.prefix, routeOpts, (req, reply) => {
reply.redirect(301, getRedirectUrl(req.raw.url))
})
}
} else {
const indexes = opts.index === undefined ? ['index.html'] : [].concat(opts.index)
const indexDirs = new Map()
const routes = new Set()
const globPattern = '**/**'

const roots = Array.isArray(sendOptions.root) ? sendOptions.root : [sendOptions.root]
for (let i = 0; i < roots.length; ++i) {
const rootPath = roots[i]
const posixRootPath = rootPath.split(path.win32.sep).join(path.posix.sep)
const files = await glob(`${posixRootPath}/${globPattern}`, { follow: true, nodir: true, dot: opts.serveDotFiles })
for (let rootPath of roots) {
rootPath = rootPath.split(path.win32.sep).join(path.posix.sep)
!rootPath.endsWith('/') && (rootPath += '/')
const files = await glob('**/**', {
cwd: rootPath, absolute: false, follow: true, nodir: true, dot: opts.serveDotFiles
})

for (let i = 0; i < files.length; ++i) {
const file = files[i].split(path.win32.sep).join(path.posix.sep)
.replace(`${posixRootPath}/`, '')
const route = (prefix + file).replace(doubleForwardSlashRegex, '/')
for (let file of files) {
file = file.split(path.win32.sep).join(path.posix.sep)
const route = prefix + file

if (routes.has(route)) {
continue
Expand Down Expand Up @@ -175,7 +171,7 @@ async function fastifyStatic (fastify, opts) {
pathname,
rootPath,
rootPathOffset = 0,
pumpOptions = {},
pumpOptions,
checkedEncodings
) {
const options = Object.assign({}, sendOptions, pumpOptions)
Expand Down
90 changes: 90 additions & 0 deletions test/static.test.js
Expand Up @@ -2012,6 +2012,96 @@ t.test('register with wildcard false', t => {
})
})

t.test('register with wildcard false (trailing slash in the root)', t => {
t.plan(6)

const pluginOptions = {
root: path.join(__dirname, '/static/'),
prefix: '/assets/',
index: false,
wildcard: false
}
const fastify = Fastify({
ignoreTrailingSlash: true
})
fastify.register(fastifyStatic, pluginOptions)

fastify.get('/*', (request, reply) => {
reply.send({ hello: 'world' })
})

t.teardown(fastify.close.bind(fastify))

fastify.listen({ port: 0 }, (err) => {
t.error(err)

fastify.server.unref()

t.test('/index.css', (t) => {
t.plan(2 + GENERIC_RESPONSE_CHECK_COUNT)
simple.concat({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port + '/assets/index.css'
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
genericResponseChecks(t, response)
})
})

t.test('/not-defined', (t) => {
t.plan(3)
simple.concat({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port + '/assets/not-defined'
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.same(JSON.parse(body), { hello: 'world' })
})
})

t.test('/deep/path/for/test/purpose/foo.html', (t) => {
t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)
simple.concat({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port + '/assets/deep/path/for/test/purpose/foo.html'
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(body.toString(), deepContent)
genericResponseChecks(t, response)
})
})

t.test('/../index.js', (t) => {
t.plan(3)
simple.concat({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port + '/assets/../index.js',
followRedirect: false
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.same(JSON.parse(body), { hello: 'world' })
})
})

t.test('/index.css', t => {
t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)
simple.concat({
method: 'HEAD',
url: 'http://localhost:' + fastify.server.address().port + '/assets/index.css'
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(body.toString(), '')
genericResponseChecks(t, response)
})
})
})
})

t.test('register with wildcard string', (t) => {
t.plan(1)

Expand Down

0 comments on commit 6c66465

Please sign in to comment.