Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ async function fastifyStatic (fastify, opts) {
})

wrap.on('pipe', function () {
reply.send(wrap)
if (request.method !== 'HEAD') { reply.send(wrap) }
})

wrap.on('finish', function () {
if (request.method === 'HEAD') { reply.send() }
})

if (setHeaders !== undefined) {
Expand Down Expand Up @@ -182,6 +186,9 @@ async function fastifyStatic (fastify, opts) {
if (opts.serve !== false) {
if (opts.wildcard && typeof opts.wildcard !== 'boolean') 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) {
pumpSendToReply(req, reply, '/' + req.params['*'], sendOptions.root)
})
Expand All @@ -203,6 +210,10 @@ async function fastifyStatic (fastify, opts) {
for (let file of files) {
file = file.replace(rootPath.replace(/\\/g, '/'), '').replace(/^\//, '')
const route = encodeURI(prefix + file).replace(/\/\//g, '/')
fastify.head(route, routeOpts, function (req, reply) {
pumpSendToReply(req, reply, '/' + file, rootPath)
})

fastify.get(route, routeOpts, function (req, reply) {
pumpSendToReply(req, reply, '/' + file, rootPath)
})
Expand All @@ -216,11 +227,18 @@ async function fastifyStatic (fastify, opts) {
const pathname = dirname + (dirname.endsWith('/') ? '' : '/')
const file = '/' + pathname.replace(prefix, '')

fastify.head(pathname, routeOpts, function (req, reply) {
pumpSendToReply(req, reply, file, rootPath)
})

fastify.get(pathname, routeOpts, function (req, reply) {
pumpSendToReply(req, reply, file, rootPath)
})

if (opts.redirect === true) {
fastify.head(pathname.replace(/\/$/, ''), routeOpts, function (req, reply) {
pumpSendToReply(req, reply, file.replace(/\/$/, ''), rootPath)
})
fastify.get(pathname.replace(/\/$/, ''), routeOpts, function (req, reply) {
pumpSendToReply(req, reply, file.replace(/\/$/, ''), rootPath)
})
Expand Down
192 changes: 180 additions & 12 deletions test/static.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function genericErrorResponseChecks (t, response) {
}

t.test('register /static prefixAvoidTrailingSlash', t => {
t.plan(11)
t.plan(12)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -184,6 +184,19 @@ t.test('register /static prefixAvoidTrailingSlash', t => {
t.strictEqual(response.statusCode, 404)
})
})

t.test('file not exposed outside of the plugin', t => {
t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)
simple.concat({
method: 'HEAD',
url: 'http://localhost:' + fastify.server.address().port + '/static/index.html'
}, (err, response, body) => {
t.error(err)
t.strictEqual(response.statusCode, 200)
t.strictEqual(body.toString(), '')
genericResponseChecks(t, response)
})
})
})
})

Expand Down Expand Up @@ -333,7 +346,7 @@ t.test('register /static', t => {
})

t.test('register /static/', t => {
t.plan(11)
t.plan(12)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -362,6 +375,19 @@ t.test('register /static/', t => {
})
})

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

t.test('/static/index.css', t => {
t.plan(2 + GENERIC_RESPONSE_CHECK_COUNT)
simple.concat({
Expand Down Expand Up @@ -1472,7 +1498,7 @@ t.test('with fastify-compress', t => {
})

t.test('register /static/ with schemaHide true', t => {
t.plan(3)
t.plan(4)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -1512,7 +1538,7 @@ t.test('register /static/ with schemaHide true', t => {
})

t.test('register /static/ with schemaHide false', t => {
t.plan(3)
t.plan(4)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -1552,7 +1578,7 @@ t.test('register /static/ with schemaHide false', t => {
})

t.test('register /static/ without schemaHide', t => {
t.plan(3)
t.plan(4)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -1590,8 +1616,44 @@ t.test('register /static/ without schemaHide', t => {
})
})

t.test('fastify with exposeHeadRoutes', t => {
t.plan(2)

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

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

t.tearDown(fastify.close.bind(fastify))

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

fastify.server.unref()

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

t.test('register with wildcard false', t => {
t.plan(8)
t.plan(9)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -1699,6 +1761,19 @@ t.test('register with wildcard false', t => {
t.deepEqual(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 + '/index.css'
}, (err, response, body) => {
t.error(err)
t.strictEqual(response.statusCode, 200)
t.strictEqual(body.toString(), '')
genericResponseChecks(t, response)
})
})
})
})

Expand Down Expand Up @@ -1745,7 +1820,7 @@ t.test('register with wildcard string on multiple root paths', t => {
})

t.test('register with wildcard false and alternative index', t => {
t.plan(8)
t.plan(11)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -1779,6 +1854,19 @@ t.test('register with wildcard false and alternative index', t => {
})
})

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

t.test('/index.css', t => {
t.plan(2 + GENERIC_RESPONSE_CHECK_COUNT)
simple.concat({
Expand All @@ -1804,6 +1892,19 @@ t.test('register with wildcard false and alternative index', t => {
})
})

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

t.test('/not-defined', t => {
t.plan(3)
simple.concat({
Expand Down Expand Up @@ -1842,6 +1943,19 @@ t.test('register with wildcard false and alternative index', t => {
})
})

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

t.test('/../index.js', t => {
t.plan(3)
simple.concat({
Expand All @@ -1858,7 +1972,7 @@ t.test('register with wildcard false and alternative index', t => {
})

t.test('register /static with wildcard false and alternative index', t => {
t.plan(9)
t.plan(11)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -1893,6 +2007,19 @@ t.test('register /static with wildcard false and alternative index', t => {
})
})

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

t.test('/static/index.css', t => {
t.plan(2 + GENERIC_RESPONSE_CHECK_COUNT)
simple.concat({
Expand Down Expand Up @@ -1938,6 +2065,19 @@ t.test('register /static with wildcard false and alternative index', t => {
})
})

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

t.test('/static/not-defined', t => {
t.plan(3)
simple.concat({
Expand Down Expand Up @@ -2103,7 +2243,7 @@ t.test('register /static with redirect true', t => {
})

t.test('register /static with redirect true and wildcard false', t => {
t.plan(6)
t.plan(8)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -2161,6 +2301,20 @@ t.test('register /static with redirect true and wildcard false', t => {
})
})

t.test('/static/?a=b', t => {
t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)

simple.concat({
method: 'HEAD',
url: 'http://localhost:' + fastify.server.address().port + '/static/?a=b'
}, (err, response, body) => {
t.error(err)
t.strictEqual(response.statusCode, 200)
t.strictEqual(body.toString(), '')
genericResponseChecks(t, response)
})
})

t.test('/static/deep', t => {
t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT)

Expand Down Expand Up @@ -2211,6 +2365,20 @@ t.test('register /static with redirect true and wildcard false', t => {
genericResponseChecks(t, response)
})
})

t.test('/static/deep/path/for/test', t => {
t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)

simple.concat({
method: 'HEAD',
url: 'http://localhost:' + fastify.server.address().port + '/static/deep/path/for/test'
}, (err, response, body) => {
t.error(err)
t.strictEqual(response.statusCode, 200)
t.strictEqual(body.toString(), '')
genericResponseChecks(t, response)
})
})
})
})

Expand Down Expand Up @@ -2441,7 +2609,7 @@ t.test('inject support', async (t) => {
})

t.test('routes should use custom errorHandler premature stream close', t => {
t.plan(3)
t.plan(4)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -2473,7 +2641,7 @@ t.test('routes should use custom errorHandler premature stream close', t => {
})

t.test('routes should fallback to default errorHandler', t => {
t.plan(3)
t.plan(4)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down Expand Up @@ -2510,7 +2678,7 @@ t.test('routes should fallback to default errorHandler', t => {
})

t.test('routes use default errorHandler when fastify.errorHandler is not defined', t => {
t.plan(3)
t.plan(4)

const pluginOptions = {
root: path.join(__dirname, '/static'),
Expand Down