Skip to content

Commit 6c66465

Browse files
authored
fix: file not found errors when the root has a trailing slash (#436)
* 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
1 parent cd85aca commit 6c66465

File tree

2 files changed

+102
-16
lines changed

2 files changed

+102
-16
lines changed

index.js

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ const contentDisposition = require('content-disposition')
1313
const dirList = require('./lib/dirList')
1414

1515
const endForwardSlashRegex = /\/$/u
16-
const doubleForwardSlashRegex = /\/\//gu
1716
const asteriskRegex = /\*/gu
1817

1918
const supportedEncodings = ['br', 'gzip', 'deflate']
@@ -112,33 +111,30 @@ async function fastifyStatic (fastify, opts) {
112111
throw new Error('"wildcard" option must be a boolean')
113112
}
114113
if (opts.wildcard === undefined || opts.wildcard === true) {
115-
fastify.head(prefix + '*', routeOpts, function (req, reply) {
116-
pumpSendToReply(req, reply, '/' + req.params['*'], sendOptions.root)
117-
})
118-
fastify.get(prefix + '*', routeOpts, function (req, reply) {
114+
fastify.get(prefix + '*', { ...routeOpts, exposeHeadRoute: true }, (req, reply) => {
119115
pumpSendToReply(req, reply, '/' + req.params['*'], sendOptions.root)
120116
})
121117
if (opts.redirect === true && prefix !== opts.prefix) {
122-
fastify.get(opts.prefix, routeOpts, function (req, reply) {
118+
fastify.get(opts.prefix, routeOpts, (req, reply) => {
123119
reply.redirect(301, getRedirectUrl(req.raw.url))
124120
})
125121
}
126122
} else {
127123
const indexes = opts.index === undefined ? ['index.html'] : [].concat(opts.index)
128124
const indexDirs = new Map()
129125
const routes = new Set()
130-
const globPattern = '**/**'
131126

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

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

143139
if (routes.has(route)) {
144140
continue
@@ -175,7 +171,7 @@ async function fastifyStatic (fastify, opts) {
175171
pathname,
176172
rootPath,
177173
rootPathOffset = 0,
178-
pumpOptions = {},
174+
pumpOptions,
179175
checkedEncodings
180176
) {
181177
const options = Object.assign({}, sendOptions, pumpOptions)

test/static.test.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2012,6 +2012,96 @@ t.test('register with wildcard false', t => {
20122012
})
20132013
})
20142014

2015+
t.test('register with wildcard false (trailing slash in the root)', t => {
2016+
t.plan(6)
2017+
2018+
const pluginOptions = {
2019+
root: path.join(__dirname, '/static/'),
2020+
prefix: '/assets/',
2021+
index: false,
2022+
wildcard: false
2023+
}
2024+
const fastify = Fastify({
2025+
ignoreTrailingSlash: true
2026+
})
2027+
fastify.register(fastifyStatic, pluginOptions)
2028+
2029+
fastify.get('/*', (request, reply) => {
2030+
reply.send({ hello: 'world' })
2031+
})
2032+
2033+
t.teardown(fastify.close.bind(fastify))
2034+
2035+
fastify.listen({ port: 0 }, (err) => {
2036+
t.error(err)
2037+
2038+
fastify.server.unref()
2039+
2040+
t.test('/index.css', (t) => {
2041+
t.plan(2 + GENERIC_RESPONSE_CHECK_COUNT)
2042+
simple.concat({
2043+
method: 'GET',
2044+
url: 'http://localhost:' + fastify.server.address().port + '/assets/index.css'
2045+
}, (err, response, body) => {
2046+
t.error(err)
2047+
t.equal(response.statusCode, 200)
2048+
genericResponseChecks(t, response)
2049+
})
2050+
})
2051+
2052+
t.test('/not-defined', (t) => {
2053+
t.plan(3)
2054+
simple.concat({
2055+
method: 'GET',
2056+
url: 'http://localhost:' + fastify.server.address().port + '/assets/not-defined'
2057+
}, (err, response, body) => {
2058+
t.error(err)
2059+
t.equal(response.statusCode, 200)
2060+
t.same(JSON.parse(body), { hello: 'world' })
2061+
})
2062+
})
2063+
2064+
t.test('/deep/path/for/test/purpose/foo.html', (t) => {
2065+
t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)
2066+
simple.concat({
2067+
method: 'GET',
2068+
url: 'http://localhost:' + fastify.server.address().port + '/assets/deep/path/for/test/purpose/foo.html'
2069+
}, (err, response, body) => {
2070+
t.error(err)
2071+
t.equal(response.statusCode, 200)
2072+
t.equal(body.toString(), deepContent)
2073+
genericResponseChecks(t, response)
2074+
})
2075+
})
2076+
2077+
t.test('/../index.js', (t) => {
2078+
t.plan(3)
2079+
simple.concat({
2080+
method: 'GET',
2081+
url: 'http://localhost:' + fastify.server.address().port + '/assets/../index.js',
2082+
followRedirect: false
2083+
}, (err, response, body) => {
2084+
t.error(err)
2085+
t.equal(response.statusCode, 200)
2086+
t.same(JSON.parse(body), { hello: 'world' })
2087+
})
2088+
})
2089+
2090+
t.test('/index.css', t => {
2091+
t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)
2092+
simple.concat({
2093+
method: 'HEAD',
2094+
url: 'http://localhost:' + fastify.server.address().port + '/assets/index.css'
2095+
}, (err, response, body) => {
2096+
t.error(err)
2097+
t.equal(response.statusCode, 200)
2098+
t.equal(body.toString(), '')
2099+
genericResponseChecks(t, response)
2100+
})
2101+
})
2102+
})
2103+
})
2104+
20152105
t.test('register with wildcard string', (t) => {
20162106
t.plan(1)
20172107

0 commit comments

Comments
 (0)