From e9b7b16f844d3fe7e9ad94f82d51d36061a36e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrg=C3=BCn=20Day=C4=B1o=C4=9Flu?= Date: Wed, 7 Feb 2024 00:43:11 +0100 Subject: [PATCH 1/8] fix not found --- index.js | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index df76735c..d9dcf0f5 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,7 @@ const { PassThrough } = require('node:stream') const path = require('node:path') const { fileURLToPath } = require('node:url') const { statSync } = require('node:fs') -const { glob } = require('glob') +const { Glob } = require('glob') const fp = require('fastify-plugin') const send = require('@fastify/send') const encodingNegotiator = require('@fastify/accept-negotiator') @@ -12,9 +12,8 @@ const contentDisposition = require('content-disposition') const dirList = require('./lib/dirList') -const endForwardSlashRegex = /\/$/u -const doubleForwardSlashRegex = /\/\//gu const asteriskRegex = /\*/gu +const endForwardSlashRegex = /\/$/u const supportedEncodings = ['br', 'gzip', 'deflate'] send.mime.default_type = 'application/octet-stream' @@ -112,11 +111,14 @@ 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) { - pumpSendToReply(req, reply, '/' + req.params['*'], sendOptions.root) + fastify.route({ + ...routeOpts, + exposeHeadRoute: true, + method: 'GET', + url: `${prefix}*`, + handler (req, reply) { + pumpSendToReply(req, reply, `/${req.params['*']}`, sendOptions.root) + } }) if (opts.redirect === true && prefix !== opts.prefix) { fastify.get(opts.prefix, routeOpts, function (req, reply) { @@ -127,18 +129,19 @@ async function fastifyStatic (fastify, opts) { 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 filesIterable = new 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 filesIterable) { + file = file.split(path.win32.sep).join(path.posix.sep) + const route = prefix + file if (routes.has(route)) { continue @@ -175,7 +178,7 @@ async function fastifyStatic (fastify, opts) { pathname, rootPath, rootPathOffset = 0, - pumpOptions = {}, + pumpOptions, checkedEncodings ) { const options = Object.assign({}, sendOptions, pumpOptions) @@ -381,7 +384,8 @@ async function fastifyStatic (fastify, opts) { function setUpHeadAndGet (routeOpts, route, file, rootPath) { const toSetUp = Object.assign({}, routeOpts, { - method: ['HEAD', 'GET'], + exposeHeadRoute: true, + method: 'GET', url: route, handler: serveFileHandler }) From 9bfbe5dc54e9e6d6c0f93c73d64a28ce5914a246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrg=C3=BCn=20Day=C4=B1o=C4=9Flu?= Date: Wed, 7 Feb 2024 01:00:03 +0100 Subject: [PATCH 2/8] fix not found --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index d9dcf0f5..41d07005 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,7 @@ const { PassThrough } = require('node:stream') const path = require('node:path') const { fileURLToPath } = require('node:url') const { statSync } = require('node:fs') -const { Glob } = require('glob') +const { glob } = require('glob') const fp = require('fastify-plugin') const send = require('@fastify/send') const encodingNegotiator = require('@fastify/accept-negotiator') @@ -135,11 +135,11 @@ async function fastifyStatic (fastify, opts) { rootPath = rootPath.split(path.win32.sep).join(path.posix.sep) !rootPath.endsWith('/') && (rootPath += '/') - const filesIterable = new Glob('**/**', { + const files = await glob('**/**', { cwd: rootPath, absolute: false, follow: true, nodir: true, dot: opts.serveDotFiles }) - for (let file of filesIterable) { + for (let file of files) { file = file.split(path.win32.sep).join(path.posix.sep) const route = prefix + file From df1a5e657b510d12aa0e261ac07cd6ac2caf36a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrg=C3=BCn=20Day=C4=B1o=C4=9Flu?= Date: Wed, 7 Feb 2024 01:05:06 +0100 Subject: [PATCH 3/8] fix not found --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 41d07005..923597bc 100644 --- a/index.js +++ b/index.js @@ -12,8 +12,8 @@ const contentDisposition = require('content-disposition') const dirList = require('./lib/dirList') -const asteriskRegex = /\*/gu const endForwardSlashRegex = /\/$/u +const asteriskRegex = /\*/gu const supportedEncodings = ['br', 'gzip', 'deflate'] send.mime.default_type = 'application/octet-stream' From 204ed48a792b9e832f9c6fe4a9af788c9cb804a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrg=C3=BCn=20Day=C4=B1o=C4=9Flu?= Date: Wed, 7 Feb 2024 01:07:27 +0100 Subject: [PATCH 4/8] fix not found --- index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/index.js b/index.js index 923597bc..3cde4520 100644 --- a/index.js +++ b/index.js @@ -134,7 +134,6 @@ async function fastifyStatic (fastify, opts) { 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 }) From 9bbd0e2a7e41db691ce6c442e8246a0e78adcf9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrg=C3=BCn=20Day=C4=B1o=C4=9Flu?= Date: Wed, 7 Feb 2024 07:06:53 +0100 Subject: [PATCH 5/8] revert change left out from the other rbanch --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 3cde4520..10c66bd5 100644 --- a/index.js +++ b/index.js @@ -384,7 +384,7 @@ async function fastifyStatic (fastify, opts) { function setUpHeadAndGet (routeOpts, route, file, rootPath) { const toSetUp = Object.assign({}, routeOpts, { exposeHeadRoute: true, - method: 'GET', + method: ['HEAD', 'GET'], url: route, handler: serveFileHandler }) From d07e1d1c12a2ae30e6fb4a3454f0542ef86b2a1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrg=C3=BCn=20Day=C4=B1o=C4=9Flu?= Date: Wed, 7 Feb 2024 07:14:20 +0100 Subject: [PATCH 6/8] revert change left out from the other rbanch --- index.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index 10c66bd5..0880cf12 100644 --- a/index.js +++ b/index.js @@ -111,14 +111,11 @@ async function fastifyStatic (fastify, opts) { throw new Error('"wildcard" option must be a boolean') } if (opts.wildcard === undefined || opts.wildcard === true) { - fastify.route({ - ...routeOpts, - exposeHeadRoute: true, - method: 'GET', - url: `${prefix}*`, - handler (req, reply) { - pumpSendToReply(req, reply, `/${req.params['*']}`, sendOptions.root) - } + 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) }) if (opts.redirect === true && prefix !== opts.prefix) { fastify.get(opts.prefix, routeOpts, function (req, reply) { @@ -383,7 +380,6 @@ async function fastifyStatic (fastify, opts) { function setUpHeadAndGet (routeOpts, route, file, rootPath) { const toSetUp = Object.assign({}, routeOpts, { - exposeHeadRoute: true, method: ['HEAD', 'GET'], url: route, handler: serveFileHandler From 051a00618147a91e71c0195927ec7b2554cb26bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrg=C3=BCn=20Day=C4=B1o=C4=9Flu?= Date: Wed, 7 Feb 2024 10:07:58 +0100 Subject: [PATCH 7/8] test --- test/static.test.js | 90 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/test/static.test.js b/test/static.test.js index a42d9dd0..abf2a8df 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -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) From 5a851f0b94bc6880ba6e8d19b079960ed8a1517e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrg=C3=BCn=20Day=C4=B1o=C4=9Flu?= Date: Wed, 7 Feb 2024 10:58:54 +0100 Subject: [PATCH 8/8] use one handler for GET and HEAD --- index.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 0880cf12..1831e5ae 100644 --- a/index.js +++ b/index.js @@ -111,14 +111,11 @@ 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)) }) }