fastify-static
Advanced tools
Comparing version
43
index.js
@@ -45,2 +45,13 @@ 'use strict' | ||
if (opts.prefix === undefined) opts.prefix = '/' | ||
let prefix = opts.prefix | ||
if (!opts.prefixAvoidTrailingSlash) { | ||
prefix = | ||
opts.prefix[opts.prefix.length - 1] === '/' | ||
? opts.prefix | ||
: opts.prefix + '/' | ||
} | ||
function pumpSendToReply ( | ||
@@ -150,3 +161,4 @@ request, | ||
options: opts.list, | ||
route: pathname | ||
route: pathname, | ||
prefix | ||
}).catch((err) => reply.send(err)) | ||
@@ -160,2 +172,4 @@ return | ||
} catch (error) { | ||
// the try-catch here is actually unreachable, but we keep it for safety and prevent DoS attack | ||
/* istanbul ignore next */ | ||
reply.send(error) | ||
@@ -176,3 +190,4 @@ } | ||
options: opts.list, | ||
route: pathname | ||
route: pathname, | ||
prefix | ||
}).catch((err) => reply.send(err)) | ||
@@ -221,13 +236,2 @@ return | ||
if (opts.prefix === undefined) opts.prefix = '/' | ||
let prefix = opts.prefix | ||
if (!opts.prefixAvoidTrailingSlash) { | ||
prefix = | ||
opts.prefix[opts.prefix.length - 1] === '/' | ||
? opts.prefix | ||
: opts.prefix + '/' | ||
} | ||
const errorHandler = (error, request, reply) => { | ||
@@ -455,6 +459,9 @@ if (error && error.code === 'ERR_STREAM_PREMATURE_CLOSE') { | ||
function getRedirectUrl (url) { | ||
if (url.startsWith('//') || url.startsWith('/\\')) { | ||
// malicous redirect | ||
return '/' | ||
let i = 0 | ||
// we detech how many slash before a valid path | ||
for (i; i < url.length; i++) { | ||
if (url[i] !== '/' && url[i] !== '\\') break | ||
} | ||
// turns all leading / or \ into a single / | ||
url = '/' + url.substr(i) | ||
try { | ||
@@ -464,4 +471,8 @@ const parsed = new URL(url, 'http://localhost.com/') | ||
} catch (error) { | ||
// the try-catch here is actually unreachable, but we keep it for safety and prevent DoS attack | ||
/* istanbul ignore next */ | ||
const err = new Error(`Invalid redirect URL: ${url}`) | ||
/* istanbul ignore next */ | ||
err.statusCode = 400 | ||
/* istanbul ignore next */ | ||
throw err | ||
@@ -468,0 +479,0 @@ } |
@@ -101,3 +101,3 @@ 'use strict' | ||
*/ | ||
send: async function ({ reply, dir, options, route }) { | ||
send: async function ({ reply, dir, options, route, prefix }) { | ||
let entries | ||
@@ -124,4 +124,4 @@ try { | ||
const html = options.render( | ||
entries.dirs.map(entry => dirList.htmlInfo(entry, route)), | ||
entries.files.map(entry => dirList.htmlInfo(entry, route))) | ||
entries.dirs.map(entry => dirList.htmlInfo(entry, route, prefix, options)), | ||
entries.files.map(entry => dirList.htmlInfo(entry, route, prefix, options))) | ||
reply.type('text/html').send(html) | ||
@@ -136,4 +136,12 @@ }, | ||
*/ | ||
htmlInfo: function (entry, route) { | ||
return { href: path.join(path.dirname(route), entry.name).replace(/\\/g, '/'), name: entry.name, stats: entry.stats, extendedInfo: entry.extendedInfo } | ||
htmlInfo: function (entry, route, prefix, options) { | ||
if (options.names && options.names.includes(path.basename(route))) { | ||
route = path.normalize(path.join(route, '..')) | ||
} | ||
return { | ||
href: path.join(prefix, route, entry.name).replace(/\\/g, '/'), | ||
name: entry.name, | ||
stats: entry.stats, | ||
extendedInfo: entry.extendedInfo | ||
} | ||
}, | ||
@@ -140,0 +148,0 @@ |
{ | ||
"name": "fastify-static", | ||
"version": "4.4.1", | ||
"version": "4.4.2", | ||
"description": "Plugin for serving static files as fast as possible.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -53,3 +53,3 @@ 'use strict' | ||
format: 'html' | ||
// no render function | ||
// no render function | ||
} | ||
@@ -163,12 +163,12 @@ }, | ||
<ul> | ||
<li><a href="/deep">deep</a></li> | ||
<li><a href="/shallow">shallow</a></li> | ||
<li><a href="/public/deep">deep</a></li> | ||
<li><a href="/public/shallow">shallow</a></li> | ||
</ul> | ||
<ul> | ||
<li><a href="/.example" target="_blank">.example</a></li> | ||
<li><a href="/a .md" target="_blank">a .md</a></li> | ||
<li><a href="/foo.html" target="_blank">foo.html</a></li> | ||
<li><a href="/foobar.html" target="_blank">foobar.html</a></li> | ||
<li><a href="/index.css" target="_blank">index.css</a></li> | ||
<li><a href="/index.html" target="_blank">index.html</a></li> | ||
<li><a href="/public/.example" target="_blank">.example</a></li> | ||
<li><a href="/public/a .md" target="_blank">a .md</a></li> | ||
<li><a href="/public/foo.html" target="_blank">foo.html</a></li> | ||
<li><a href="/public/foobar.html" target="_blank">foobar.html</a></li> | ||
<li><a href="/public/index.css" target="_blank">index.css</a></li> | ||
<li><a href="/public/index.html" target="_blank">index.html</a></li> | ||
</ul> | ||
@@ -195,12 +195,12 @@ </body></html> | ||
<ul> | ||
<li><a href="/deep">deep</a></li> | ||
<li><a href="/shallow">shallow</a></li> | ||
<li><a href="/public/deep">deep</a></li> | ||
<li><a href="/public/shallow">shallow</a></li> | ||
</ul> | ||
<ul> | ||
<li><a href="/.example" target="_blank">.example</a></li> | ||
<li><a href="/a .md" target="_blank">a .md</a></li> | ||
<li><a href="/foo.html" target="_blank">foo.html</a></li> | ||
<li><a href="/foobar.html" target="_blank">foobar.html</a></li> | ||
<li><a href="/index.css" target="_blank">index.css</a></li> | ||
<li><a href="/index.html" target="_blank">index.html</a></li> | ||
<li><a href="/public/.example" target="_blank">.example</a></li> | ||
<li><a href="/public/a .md" target="_blank">a .md</a></li> | ||
<li><a href="/public/foo.html" target="_blank">foo.html</a></li> | ||
<li><a href="/public/foobar.html" target="_blank">foobar.html</a></li> | ||
<li><a href="/public/index.css" target="_blank">index.css</a></li> | ||
<li><a href="/public/index.html" target="_blank">index.html</a></li> | ||
</ul> | ||
@@ -246,2 +246,49 @@ </body></html> | ||
t.test('dir list href nested structure', t => { | ||
t.plan(6) | ||
const options = { | ||
root: path.join(__dirname, '/static'), | ||
prefix: '/public', | ||
index: false, | ||
list: { | ||
format: 'html', | ||
names: ['index', 'index.htm'], | ||
render (dirs, files) { | ||
return dirs[0].href | ||
} | ||
} | ||
} | ||
const routes = [ | ||
{ path: '/public/', response: '/public/deep' }, | ||
{ path: '/public/index', response: '/public/deep' }, | ||
{ path: '/public/deep/', response: '/public/deep/path' }, | ||
{ path: '/public/deep/index.htm', response: '/public/deep/path' }, | ||
{ path: '/public/deep/path/', response: '/public/deep/path/for' } | ||
] | ||
helper.arrange(t, options, (url) => { | ||
for (const route of routes) { | ||
t.test(route.path, t => { | ||
t.plan(5) | ||
simple.concat({ | ||
method: 'GET', | ||
url: url + route.path | ||
}, (err, response, body) => { | ||
t.error(err) | ||
t.equal(response.statusCode, 200) | ||
t.equal(body.toString(), route.response) | ||
simple.concat({ | ||
method: 'GET', | ||
url: url + body.toString() | ||
}, (err, response, body) => { | ||
t.error(err) | ||
t.equal(response.statusCode, 200) | ||
}) | ||
}) | ||
}) | ||
} | ||
}) | ||
}) | ||
t.test('dir list html format - stats', t => { | ||
@@ -248,0 +295,0 @@ t.plan(7) |
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
349182
0.63%4316
1.51%