@fastify/static 7.0.3 → 8.0.0-pre.fv5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +0 -0
- package/.gitattributes +0 -0
- package/.github/dependabot.yml +0 -0
- package/.github/stale.yml +0 -0
- package/.github/workflows/ci.yml +1 -1
- package/.taprc +0 -0
- package/LICENSE +0 -0
- package/README.md +3 -3
- package/example/public/.hidden/sample.json +0 -0
- package/example/public/images/sample.jpg +0 -0
- package/example/public/index.css +0 -0
- package/example/public/index.html +0 -0
- package/example/public/index.js +0 -0
- package/example/public2/test.css +0 -0
- package/example/public2/test.html +0 -0
- package/example/server-compress.js +0 -0
- package/example/server-dir-list.js +0 -0
- package/example/server-hidden-file.js +0 -0
- package/example/server.js +0 -0
- package/index.js +128 -149
- package/lib/dirList.js +4 -4
- package/package.json +21 -22
- package/test/content-type/binary +0 -0
- package/test/content-type/binary.br +0 -0
- package/test/content-type/index.css +0 -0
- package/test/content-type/index.css.br +0 -0
- package/test/content-type/index.html +0 -0
- package/test/content-type/index.html.br +0 -0
- package/test/content-type/sample.jpg +0 -0
- package/test/content-type/test.txt +0 -0
- package/test/content-type/test.txt.br +0 -0
- package/test/content-type.test.js +0 -0
- package/test/dir-list.test.js +38 -8
- package/test/static/.example +0 -0
- package/test/static/100%.txt +1 -0
- package/test/static/a .md +0 -0
- package/test/static/deep/path/for/test/index.html +0 -0
- package/test/static/deep/path/for/test/purpose/foo.html +0 -0
- package/test/static/foo.html +0 -0
- package/test/static/foobar.html +0 -0
- package/test/static/index.css +0 -0
- package/test/static/index.html +0 -0
- package/test/static/shallow/sample.jpg +0 -0
- package/test/static-dotfiles/.aaa +0 -0
- package/test/static-dotfiles/dir/index.html +0 -0
- package/test/static-dotfiles/test.txt +0 -0
- package/test/static-encode/[...]/a .md +0 -0
- package/test/static-hidden/.hidden/sample.json +0 -0
- package/test/static-pre-compressed/all-three.html +0 -0
- package/test/static-pre-compressed/all-three.html.br +0 -0
- package/test/static-pre-compressed/all-three.html.gz +0 -0
- package/test/static-pre-compressed/dir/index.html +0 -0
- package/test/static-pre-compressed/dir/index.html.br +0 -0
- package/test/static-pre-compressed/dir-gz/index.html +0 -0
- package/test/static-pre-compressed/dir-gz/index.html.gz +0 -0
- package/test/static-pre-compressed/empty/.gitkeep +0 -0
- package/test/static-pre-compressed/gzip-only.html +0 -0
- package/test/static-pre-compressed/gzip-only.html.gz +0 -0
- package/test/static-pre-compressed/index.html +0 -0
- package/test/static-pre-compressed/index.html.br +0 -0
- package/test/static-pre-compressed/sample.jpg +0 -0
- package/test/static-pre-compressed/sample.jpg.br +0 -0
- package/test/static-pre-compressed/uncompressed.html +0 -0
- package/test/static-symbolic-link/origin/subdir/subdir/index.html +0 -0
- package/test/static.test.js +31 -4
- package/test/static2/bar.html +0 -0
- package/test/static2/index.html +0 -0
- package/tsconfig.eslint.json +0 -0
- package/types/index.d.ts +0 -0
- package/types/index.test-d.ts +0 -0
package/.eslintrc.json
CHANGED
|
File without changes
|
package/.gitattributes
CHANGED
|
File without changes
|
package/.github/dependabot.yml
CHANGED
|
File without changes
|
package/.github/stale.yml
CHANGED
|
File without changes
|
package/.github/workflows/ci.yml
CHANGED
package/.taprc
CHANGED
|
File without changes
|
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -477,13 +477,13 @@ If an error occurs while trying to send a file, the error will be passed
|
|
|
477
477
|
to Fastify's error handler. You can set a custom error handler with
|
|
478
478
|
[`fastify.setErrorHandler()`](https://fastify.dev/docs/latest/Reference/Server/#seterrorhandler).
|
|
479
479
|
|
|
480
|
-
### Payload `stream.
|
|
480
|
+
### Payload `stream.path`
|
|
481
481
|
|
|
482
|
-
If you need to access the
|
|
482
|
+
If you need to access the file path inside the `onSend` hook, you can use `payload.path`.
|
|
483
483
|
|
|
484
484
|
```js
|
|
485
485
|
fastify.addHook('onSend', function (req, reply, payload, next) {
|
|
486
|
-
console.log(payload.
|
|
486
|
+
console.log(payload.path)
|
|
487
487
|
next()
|
|
488
488
|
})
|
|
489
489
|
```
|
|
File without changes
|
|
File without changes
|
package/example/public/index.css
CHANGED
|
File without changes
|
|
File without changes
|
package/example/public/index.js
CHANGED
|
File without changes
|
package/example/public2/test.css
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/example/server.js
CHANGED
|
File without changes
|
package/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { PassThrough } = require('node:stream')
|
|
4
3
|
const path = require('node:path')
|
|
5
4
|
const { fileURLToPath } = require('node:url')
|
|
6
5
|
const { statSync } = require('node:fs')
|
|
@@ -121,7 +120,7 @@ async function fastifyStatic (fastify, opts) {
|
|
|
121
120
|
})
|
|
122
121
|
if (opts.redirect === true && prefix !== opts.prefix) {
|
|
123
122
|
fastify.get(opts.prefix, routeOpts, (req, reply) => {
|
|
124
|
-
reply.redirect(
|
|
123
|
+
reply.redirect(getRedirectUrl(req.raw.url), 301)
|
|
125
124
|
})
|
|
126
125
|
}
|
|
127
126
|
} else {
|
|
@@ -170,7 +169,7 @@ async function fastifyStatic (fastify, opts) {
|
|
|
170
169
|
|
|
171
170
|
const allowedPath = opts.allowedPath
|
|
172
171
|
|
|
173
|
-
function pumpSendToReply (
|
|
172
|
+
async function pumpSendToReply (
|
|
174
173
|
request,
|
|
175
174
|
reply,
|
|
176
175
|
pathname,
|
|
@@ -221,164 +220,149 @@ async function fastifyStatic (fastify, opts) {
|
|
|
221
220
|
}
|
|
222
221
|
}
|
|
223
222
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
223
|
+
// `send(..., path, ...)` will URI-decode path so we pass an encoded path here
|
|
224
|
+
const {
|
|
225
|
+
statusCode,
|
|
226
|
+
headers,
|
|
227
|
+
stream,
|
|
228
|
+
type,
|
|
229
|
+
metadata
|
|
230
|
+
} = await send(request.raw, encodeURI(pathnameForSend), options)
|
|
231
|
+
switch (type) {
|
|
232
|
+
case 'directory': {
|
|
233
|
+
const path = metadata.path
|
|
234
|
+
if (opts.list) {
|
|
235
|
+
await dirList.send({
|
|
236
|
+
reply,
|
|
237
|
+
dir: path,
|
|
238
|
+
options: opts.list,
|
|
239
|
+
route: pathname,
|
|
240
|
+
prefix,
|
|
241
|
+
dotfiles: opts.dotfiles
|
|
242
|
+
}).catch((err) => reply.send(err))
|
|
235
243
|
}
|
|
236
|
-
cb()
|
|
237
|
-
}
|
|
238
|
-
})
|
|
239
244
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
245
|
+
if (opts.redirect === true) {
|
|
246
|
+
try {
|
|
247
|
+
reply.redirect(getRedirectUrl(request.raw.url), 301)
|
|
248
|
+
} /* c8 ignore start */ catch (error) {
|
|
249
|
+
// the try-catch here is actually unreachable, but we keep it for safety and prevent DoS attack
|
|
250
|
+
await reply.send(error)
|
|
251
|
+
} /* c8 ignore stop */
|
|
252
|
+
} else {
|
|
253
|
+
// if is a directory path without a trailing slash, and has an index file, reply as if it has a trailing slash
|
|
254
|
+
if (!pathname.endsWith('/') && findIndexFile(pathname, options.root, options.index)) {
|
|
255
|
+
return pumpSendToReply(
|
|
256
|
+
request,
|
|
257
|
+
reply,
|
|
258
|
+
pathname + '/',
|
|
259
|
+
rootPath,
|
|
260
|
+
undefined,
|
|
261
|
+
undefined,
|
|
262
|
+
checkedEncodings
|
|
263
|
+
)
|
|
264
|
+
}
|
|
244
265
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
})
|
|
250
|
-
Object.defineProperty(wrap, 'statusCode', {
|
|
251
|
-
get () {
|
|
252
|
-
return reply.raw.statusCode
|
|
253
|
-
},
|
|
254
|
-
set (code) {
|
|
255
|
-
reply.code(code)
|
|
266
|
+
reply.callNotFound()
|
|
267
|
+
}
|
|
268
|
+
break
|
|
256
269
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
270
|
+
case 'error': {
|
|
271
|
+
if (
|
|
272
|
+
statusCode === 403 &&
|
|
273
|
+
(!options.index || !options.index.length) &&
|
|
274
|
+
pathnameForSend[pathnameForSend.length - 1] === '/'
|
|
275
|
+
) {
|
|
276
|
+
if (opts.list) {
|
|
277
|
+
await dirList.send({
|
|
278
|
+
reply,
|
|
279
|
+
dir: dirList.path(opts.root, pathname),
|
|
280
|
+
options: opts.list,
|
|
281
|
+
route: pathname,
|
|
282
|
+
prefix,
|
|
283
|
+
dotfiles: opts.dotfiles
|
|
284
|
+
}).catch((err) => reply.send(err))
|
|
285
|
+
}
|
|
266
286
|
}
|
|
267
|
-
reply.send(wrap)
|
|
268
|
-
})
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (setHeaders !== undefined) {
|
|
272
|
-
stream.on('headers', setHeaders)
|
|
273
|
-
}
|
|
274
287
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
288
|
+
if (metadata.error.code === 'ENOENT') {
|
|
289
|
+
// when preCompress is enabled and the path is a directory without a trailing slash
|
|
290
|
+
if (opts.preCompressed && encoding) {
|
|
291
|
+
const indexPathname = findIndexFile(pathname, options.root, options.index)
|
|
292
|
+
if (indexPathname) {
|
|
293
|
+
return pumpSendToReply(
|
|
294
|
+
request,
|
|
295
|
+
reply,
|
|
296
|
+
pathname + '/',
|
|
297
|
+
rootPath,
|
|
298
|
+
undefined,
|
|
299
|
+
undefined,
|
|
300
|
+
checkedEncodings
|
|
301
|
+
)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
287
304
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
request,
|
|
301
|
-
reply,
|
|
302
|
-
pathname + '/',
|
|
303
|
-
rootPath,
|
|
304
|
-
undefined,
|
|
305
|
-
undefined,
|
|
306
|
-
checkedEncodings
|
|
307
|
-
)
|
|
308
|
-
}
|
|
305
|
+
// if file exists, send real file, otherwise send dir list if name match
|
|
306
|
+
if (opts.list && dirList.handle(pathname, opts.list)) {
|
|
307
|
+
await dirList.send({
|
|
308
|
+
reply,
|
|
309
|
+
dir: dirList.path(opts.root, pathname),
|
|
310
|
+
options: opts.list,
|
|
311
|
+
route: pathname,
|
|
312
|
+
prefix,
|
|
313
|
+
dotfiles: opts.dotfiles
|
|
314
|
+
}).catch((err) => reply.send(err))
|
|
315
|
+
return
|
|
316
|
+
}
|
|
309
317
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
318
|
+
// root paths left to try?
|
|
319
|
+
if (Array.isArray(rootPath) && rootPathOffset < (rootPath.length - 1)) {
|
|
320
|
+
return pumpSendToReply(request, reply, pathname, rootPath, rootPathOffset + 1)
|
|
321
|
+
}
|
|
313
322
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
// when preCompress is enabled and the path is a directory without a trailing slash
|
|
317
|
-
if (opts.preCompressed && encoding) {
|
|
318
|
-
const indexPathname = findIndexFile(pathname, options.root, options.index)
|
|
319
|
-
if (indexPathname) {
|
|
323
|
+
if (opts.preCompressed && !checkedEncodings.has(encoding)) {
|
|
324
|
+
checkedEncodings.add(encoding)
|
|
320
325
|
return pumpSendToReply(
|
|
321
326
|
request,
|
|
322
327
|
reply,
|
|
323
|
-
|
|
328
|
+
pathnameOrig,
|
|
324
329
|
rootPath,
|
|
325
|
-
|
|
330
|
+
rootPathOffset,
|
|
326
331
|
undefined,
|
|
327
332
|
checkedEncodings
|
|
328
333
|
)
|
|
329
334
|
}
|
|
330
|
-
}
|
|
331
335
|
|
|
332
|
-
|
|
333
|
-
if (opts.list && dirList.handle(pathname, opts.list)) {
|
|
334
|
-
dirList.send({
|
|
335
|
-
reply,
|
|
336
|
-
dir: dirList.path(opts.root, pathname),
|
|
337
|
-
options: opts.list,
|
|
338
|
-
route: pathname,
|
|
339
|
-
prefix,
|
|
340
|
-
dotfiles: opts.dotfiles
|
|
341
|
-
}).catch((err) => reply.send(err))
|
|
342
|
-
return
|
|
336
|
+
return reply.callNotFound()
|
|
343
337
|
}
|
|
344
338
|
|
|
345
|
-
//
|
|
346
|
-
|
|
347
|
-
|
|
339
|
+
// The `send` library terminates the request with a 404 if the requested
|
|
340
|
+
// path contains a dotfile and `send` is initialized with `{dotfiles:
|
|
341
|
+
// 'ignore'}`. `send` aborts the request before getting far enough to
|
|
342
|
+
// check if the file exists (hence, a 404 `NotFoundError` instead of
|
|
343
|
+
// `ENOENT`).
|
|
344
|
+
// https://github.com/pillarjs/send/blob/de073ed3237ade9ff71c61673a34474b30e5d45b/index.js#L582
|
|
345
|
+
if (metadata.error.status === 404) {
|
|
346
|
+
return reply.callNotFound()
|
|
348
347
|
}
|
|
349
348
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
return pumpSendToReply(
|
|
353
|
-
request,
|
|
354
|
-
reply,
|
|
355
|
-
pathnameOrig,
|
|
356
|
-
rootPath,
|
|
357
|
-
rootPathOffset,
|
|
358
|
-
undefined,
|
|
359
|
-
checkedEncodings
|
|
360
|
-
)
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return reply.callNotFound()
|
|
349
|
+
await reply.send(metadata.error)
|
|
350
|
+
break
|
|
364
351
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
352
|
+
case 'file': {
|
|
353
|
+
reply.code(statusCode)
|
|
354
|
+
if (setHeaders !== undefined) {
|
|
355
|
+
setHeaders(reply.raw, metadata.path, metadata.stat)
|
|
356
|
+
}
|
|
357
|
+
reply.headers(headers)
|
|
358
|
+
if (encoding) {
|
|
359
|
+
reply.header('content-type', getContentType(pathname))
|
|
360
|
+
reply.header('content-encoding', encoding)
|
|
361
|
+
}
|
|
362
|
+
await reply.send(stream)
|
|
363
|
+
break
|
|
374
364
|
}
|
|
375
|
-
|
|
376
|
-
reply.send(err)
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
// we cannot use pump, because send error
|
|
380
|
-
// handling is not compatible
|
|
381
|
-
stream.pipe(wrap)
|
|
365
|
+
}
|
|
382
366
|
}
|
|
383
367
|
|
|
384
368
|
function setUpHeadAndGet (routeOpts, route, file, rootPath) {
|
|
@@ -393,11 +377,11 @@ async function fastifyStatic (fastify, opts) {
|
|
|
393
377
|
fastify.route(toSetUp)
|
|
394
378
|
}
|
|
395
379
|
|
|
396
|
-
function serveFileHandler (req, reply) {
|
|
380
|
+
async function serveFileHandler (req, reply) {
|
|
397
381
|
// TODO: remove the fallback branch when bump major
|
|
398
|
-
/*
|
|
382
|
+
/* c8 ignore next */
|
|
399
383
|
const routeConfig = req.routeOptions?.config || req.routeConfig
|
|
400
|
-
pumpSendToReply(req, reply, routeConfig.file, routeConfig.rootPath)
|
|
384
|
+
return pumpSendToReply(req, reply, routeConfig.file, routeConfig.rootPath)
|
|
401
385
|
}
|
|
402
386
|
}
|
|
403
387
|
|
|
@@ -488,8 +472,6 @@ function getContentType (path) {
|
|
|
488
472
|
}
|
|
489
473
|
|
|
490
474
|
function findIndexFile (pathname, root, indexFiles = ['index.html']) {
|
|
491
|
-
// TODO remove istanbul ignore
|
|
492
|
-
/* istanbul ignore else */
|
|
493
475
|
if (Array.isArray(indexFiles)) {
|
|
494
476
|
return indexFiles.find(filename => {
|
|
495
477
|
const p = path.join(root, pathname, filename)
|
|
@@ -501,7 +483,7 @@ function findIndexFile (pathname, root, indexFiles = ['index.html']) {
|
|
|
501
483
|
}
|
|
502
484
|
})
|
|
503
485
|
}
|
|
504
|
-
/*
|
|
486
|
+
/* c8 ignore next */
|
|
505
487
|
return false
|
|
506
488
|
}
|
|
507
489
|
|
|
@@ -540,19 +522,16 @@ function getRedirectUrl (url) {
|
|
|
540
522
|
const parsed = new URL(url, 'http://localhost.com/')
|
|
541
523
|
const parsedPathname = parsed.pathname
|
|
542
524
|
return parsedPathname + (parsedPathname[parsedPathname.length - 1] !== '/' ? '/' : '') + (parsed.search || '')
|
|
543
|
-
} catch {
|
|
525
|
+
} /* c8 ignore start */ catch {
|
|
544
526
|
// the try-catch here is actually unreachable, but we keep it for safety and prevent DoS attack
|
|
545
|
-
/* istanbul ignore next */
|
|
546
527
|
const err = new Error(`Invalid redirect URL: ${url}`)
|
|
547
|
-
/* istanbul ignore next */
|
|
548
528
|
err.statusCode = 400
|
|
549
|
-
/* istanbul ignore next */
|
|
550
529
|
throw err
|
|
551
|
-
}
|
|
530
|
+
} /* c8 ignore stop */
|
|
552
531
|
}
|
|
553
532
|
|
|
554
533
|
module.exports = fp(fastifyStatic, {
|
|
555
|
-
fastify: '
|
|
534
|
+
fastify: '5.x',
|
|
556
535
|
name: '@fastify/static'
|
|
557
536
|
})
|
|
558
537
|
module.exports.default = fastifyStatic
|
package/lib/dirList.js
CHANGED
|
@@ -125,9 +125,9 @@ const dirList = {
|
|
|
125
125
|
entries.dirs.forEach(entry => nameEntries.dirs.push(entry.name))
|
|
126
126
|
entries.files.forEach(entry => nameEntries.files.push(entry.name))
|
|
127
127
|
|
|
128
|
-
reply.send(nameEntries)
|
|
128
|
+
await reply.send(nameEntries)
|
|
129
129
|
} else {
|
|
130
|
-
reply.send(entries)
|
|
130
|
+
await reply.send(entries)
|
|
131
131
|
}
|
|
132
132
|
return
|
|
133
133
|
}
|
|
@@ -135,7 +135,7 @@ const dirList = {
|
|
|
135
135
|
const html = options.render(
|
|
136
136
|
entries.dirs.map(entry => dirList.htmlInfo(entry, route, prefix, options)),
|
|
137
137
|
entries.files.map(entry => dirList.htmlInfo(entry, route, prefix, options)))
|
|
138
|
-
reply.type('text/html').send(html)
|
|
138
|
+
await reply.type('text/html').send(html)
|
|
139
139
|
},
|
|
140
140
|
|
|
141
141
|
/**
|
|
@@ -149,7 +149,7 @@ const dirList = {
|
|
|
149
149
|
route = path.normalize(path.join(route, '..'))
|
|
150
150
|
}
|
|
151
151
|
return {
|
|
152
|
-
href: path.join(prefix, route, entry.name).replace(/\\/gu, '/'),
|
|
152
|
+
href: encodeURI(path.join(prefix, route, entry.name).replace(/\\/gu, '/')),
|
|
153
153
|
name: entry.name,
|
|
154
154
|
stats: entry.stats,
|
|
155
155
|
extendedInfo: entry.extendedInfo
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastify/static",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0-pre.fv5.1",
|
|
4
4
|
"description": "Plugin for serving static files as fast as possible.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -31,32 +31,31 @@
|
|
|
31
31
|
},
|
|
32
32
|
"homepage": "https://github.com/fastify/fastify-static",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@fastify/accept-negotiator": "^
|
|
35
|
-
"@fastify/send": "^
|
|
36
|
-
"content-disposition": "^0.5.
|
|
37
|
-
"fastify-plugin": "^
|
|
38
|
-
"fastq": "^1.17.
|
|
39
|
-
"glob": "^10.3.
|
|
34
|
+
"@fastify/accept-negotiator": "^2.0.0-pre.fv5.1",
|
|
35
|
+
"@fastify/send": "^3.1.0",
|
|
36
|
+
"content-disposition": "^0.5.4",
|
|
37
|
+
"fastify-plugin": "^5.0.0-pre.fv5.1",
|
|
38
|
+
"fastq": "^1.17.1",
|
|
39
|
+
"glob": "^10.3.10"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@fastify/compress": "^
|
|
43
|
-
"@fastify/pre-commit": "^2.0
|
|
44
|
-
"@types/node": "^20.
|
|
45
|
-
"@typescript-eslint/eslint-plugin": "^7.1
|
|
46
|
-
"@typescript-eslint/parser": "^7.1
|
|
42
|
+
"@fastify/compress": "^8.0.0-pre.fv5.1",
|
|
43
|
+
"@fastify/pre-commit": "^2.1.0",
|
|
44
|
+
"@types/node": "^20.11.30",
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
|
46
|
+
"@typescript-eslint/parser": "^7.3.1",
|
|
47
47
|
"concat-stream": "^2.0.0",
|
|
48
|
-
"coveralls": "^3.
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"simple-get": "^4.0.0",
|
|
48
|
+
"coveralls": "^3.1.1",
|
|
49
|
+
"fastify": "^5.0.0-alpha.3",
|
|
50
|
+
"handlebars": "^4.7.8",
|
|
51
|
+
"pino": "^9.1.0",
|
|
52
|
+
"proxyquire": "^2.1.3",
|
|
53
|
+
"simple-get": "^4.0.1",
|
|
55
54
|
"snazzy": "^9.0.0",
|
|
56
|
-
"standard": "^17.
|
|
57
|
-
"tap": "^
|
|
55
|
+
"standard": "^17.1.0",
|
|
56
|
+
"tap": "^18.7.1",
|
|
58
57
|
"tsd": "^0.31.0",
|
|
59
|
-
"typescript": "^5.
|
|
58
|
+
"typescript": "^5.4.3"
|
|
60
59
|
},
|
|
61
60
|
"tsd": {
|
|
62
61
|
"directory": "test/types"
|
package/test/content-type/binary
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/test/dir-list.test.js
CHANGED
|
@@ -154,7 +154,35 @@ t.test('dir list, custom options', t => {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
const route = '/public/'
|
|
157
|
-
const content = { dirs: ['deep', 'shallow'], files: ['.example', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
|
|
157
|
+
const content = { dirs: ['deep', 'shallow'], files: ['.example', '100%.txt', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
|
|
158
|
+
|
|
159
|
+
helper.arrange(t, options, (url) => {
|
|
160
|
+
t.test(route, t => {
|
|
161
|
+
t.plan(3)
|
|
162
|
+
simple.concat({
|
|
163
|
+
method: 'GET',
|
|
164
|
+
url: url + route
|
|
165
|
+
}, (err, response, body) => {
|
|
166
|
+
t.error(err)
|
|
167
|
+
t.equal(response.statusCode, 200)
|
|
168
|
+
t.equal(body.toString(), JSON.stringify(content))
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
t.test('dir list, custom options with empty array index', t => {
|
|
175
|
+
t.plan(2)
|
|
176
|
+
|
|
177
|
+
const options = {
|
|
178
|
+
root: path.join(__dirname, '/static'),
|
|
179
|
+
prefix: '/public',
|
|
180
|
+
index: [],
|
|
181
|
+
list: true
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const route = '/public/'
|
|
185
|
+
const content = { dirs: ['deep', 'shallow'], files: ['.example', '100%.txt', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
|
|
158
186
|
|
|
159
187
|
helper.arrange(t, options, (url) => {
|
|
160
188
|
t.test(route, t => {
|
|
@@ -205,7 +233,8 @@ t.test('dir list html format', t => {
|
|
|
205
233
|
</ul>
|
|
206
234
|
<ul>
|
|
207
235
|
<li><a href="/public/.example" target="_blank">.example</a></li>
|
|
208
|
-
<li><a href="/public/
|
|
236
|
+
<li><a href="/public/100%25.txt" target="_blank">100%.txt</a></li>
|
|
237
|
+
<li><a href="/public/a%20.md" target="_blank">a .md</a></li>
|
|
209
238
|
<li><a href="/public/foo.html" target="_blank">foo.html</a></li>
|
|
210
239
|
<li><a href="/public/foobar.html" target="_blank">foobar.html</a></li>
|
|
211
240
|
<li><a href="/public/index.css" target="_blank">index.css</a></li>
|
|
@@ -236,7 +265,8 @@ t.test('dir list html format', t => {
|
|
|
236
265
|
</ul>
|
|
237
266
|
<ul>
|
|
238
267
|
<li><a href="/public/.example" target="_blank">.example</a></li>
|
|
239
|
-
<li><a href="/public/
|
|
268
|
+
<li><a href="/public/100%25.txt" target="_blank">100%.txt</a></li>
|
|
269
|
+
<li><a href="/public/a%20.md" target="_blank">a .md</a></li>
|
|
240
270
|
<li><a href="/public/foo.html" target="_blank">foo.html</a></li>
|
|
241
271
|
<li><a href="/public/foobar.html" target="_blank">foobar.html</a></li>
|
|
242
272
|
<li><a href="/public/index.css" target="_blank">index.css</a></li>
|
|
@@ -469,7 +499,7 @@ t.test('dir list json format - extended info', t => {
|
|
|
469
499
|
t.equal(response.statusCode, 200)
|
|
470
500
|
const bodyObject = JSON.parse(body.toString())
|
|
471
501
|
t.equal(bodyObject.dirs[0].name, 'empty')
|
|
472
|
-
t.equal(typeof bodyObject.dirs[0].stats.
|
|
502
|
+
t.equal(typeof bodyObject.dirs[0].stats.atimeMs, 'number')
|
|
473
503
|
t.equal(typeof bodyObject.dirs[0].extendedInfo.totalSize, 'number')
|
|
474
504
|
})
|
|
475
505
|
})
|
|
@@ -492,7 +522,7 @@ t.test('json format with url parameter format', t => {
|
|
|
492
522
|
}
|
|
493
523
|
}
|
|
494
524
|
const route = '/public/'
|
|
495
|
-
const jsonContent = { dirs: ['deep', 'shallow'], files: ['.example', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
|
|
525
|
+
const jsonContent = { dirs: ['deep', 'shallow'], files: ['.example', '100%.txt', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
|
|
496
526
|
|
|
497
527
|
helper.arrange(t, options, (url) => {
|
|
498
528
|
simple.concat({
|
|
@@ -539,7 +569,7 @@ t.test('json format with url parameter format and without render option', t => {
|
|
|
539
569
|
}
|
|
540
570
|
}
|
|
541
571
|
const route = '/public/'
|
|
542
|
-
const jsonContent = { dirs: ['deep', 'shallow'], files: ['.example', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
|
|
572
|
+
const jsonContent = { dirs: ['deep', 'shallow'], files: ['.example', '100%.txt', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
|
|
543
573
|
|
|
544
574
|
helper.arrange(t, options, (url) => {
|
|
545
575
|
simple.concat({
|
|
@@ -588,7 +618,7 @@ t.test('html format with url parameter format', t => {
|
|
|
588
618
|
}
|
|
589
619
|
}
|
|
590
620
|
const route = '/public/'
|
|
591
|
-
const jsonContent = { dirs: ['deep', 'shallow'], files: ['.example', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
|
|
621
|
+
const jsonContent = { dirs: ['deep', 'shallow'], files: ['.example', '100%.txt', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
|
|
592
622
|
|
|
593
623
|
helper.arrange(t, options, (url) => {
|
|
594
624
|
simple.concat({
|
|
@@ -843,7 +873,7 @@ t.test('dir list error', t => {
|
|
|
843
873
|
const errorMessage = 'mocking send'
|
|
844
874
|
dirList.send = async () => { throw new Error(errorMessage) }
|
|
845
875
|
|
|
846
|
-
const mock = t.
|
|
876
|
+
const mock = t.mockRequire('..', {
|
|
847
877
|
'../lib/dirList.js': dirList
|
|
848
878
|
})
|
|
849
879
|
|
package/test/static/.example
CHANGED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
100%
|
package/test/static/a .md
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/test/static/foo.html
CHANGED
|
File without changes
|
package/test/static/foobar.html
CHANGED
|
File without changes
|
package/test/static/index.css
CHANGED
|
File without changes
|
package/test/static/index.html
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/test/static.test.js
CHANGED
|
@@ -681,7 +681,7 @@ t.test('register /static with constraints', (t) => {
|
|
|
681
681
|
})
|
|
682
682
|
})
|
|
683
683
|
|
|
684
|
-
t.test('payload.
|
|
684
|
+
t.test('payload.path is set', (t) => {
|
|
685
685
|
t.plan(3)
|
|
686
686
|
|
|
687
687
|
const pluginOptions = {
|
|
@@ -692,7 +692,7 @@ t.test('payload.filename is set', (t) => {
|
|
|
692
692
|
let gotFilename
|
|
693
693
|
fastify.register(fastifyStatic, pluginOptions)
|
|
694
694
|
fastify.addHook('onSend', function (req, reply, payload, next) {
|
|
695
|
-
gotFilename = payload.
|
|
695
|
+
gotFilename = payload.path
|
|
696
696
|
next()
|
|
697
697
|
})
|
|
698
698
|
|
|
@@ -1361,13 +1361,13 @@ t.test('root not found warning', (t) => {
|
|
|
1361
1361
|
const destination = concat((data) => {
|
|
1362
1362
|
t.equal(JSON.parse(data).msg, `"root" path "${rootPath}" must exist`)
|
|
1363
1363
|
})
|
|
1364
|
-
const
|
|
1364
|
+
const loggerInstance = pino(
|
|
1365
1365
|
{
|
|
1366
1366
|
level: 'warn'
|
|
1367
1367
|
},
|
|
1368
1368
|
destination
|
|
1369
1369
|
)
|
|
1370
|
-
const fastify = Fastify({
|
|
1370
|
+
const fastify = Fastify({ loggerInstance })
|
|
1371
1371
|
fastify.register(fastifyStatic, pluginOptions)
|
|
1372
1372
|
fastify.listen({ port: 0 }, (err) => {
|
|
1373
1373
|
t.error(err)
|
|
@@ -3963,6 +3963,33 @@ t.test(
|
|
|
3963
3963
|
}
|
|
3964
3964
|
)
|
|
3965
3965
|
|
|
3966
|
+
t.test(
|
|
3967
|
+
'serves files with % in the filename',
|
|
3968
|
+
async (t) => {
|
|
3969
|
+
t.plan(2)
|
|
3970
|
+
|
|
3971
|
+
const txtContent = fs.readFileSync(path.join(__dirname, 'static', '100%.txt'), 'utf-8')
|
|
3972
|
+
|
|
3973
|
+
const pluginOptions = {
|
|
3974
|
+
root: url.pathToFileURL(path.join(__dirname, '/static')),
|
|
3975
|
+
wildcard: false
|
|
3976
|
+
}
|
|
3977
|
+
|
|
3978
|
+
const fastify = Fastify()
|
|
3979
|
+
|
|
3980
|
+
fastify.register(fastifyStatic, pluginOptions)
|
|
3981
|
+
const response = await fastify.inject({
|
|
3982
|
+
method: 'GET',
|
|
3983
|
+
url: '100%25.txt',
|
|
3984
|
+
headers: {
|
|
3985
|
+
'accept-encoding': '*, *'
|
|
3986
|
+
}
|
|
3987
|
+
})
|
|
3988
|
+
t.equal(response.statusCode, 200)
|
|
3989
|
+
t.same(response.body, txtContent)
|
|
3990
|
+
}
|
|
3991
|
+
)
|
|
3992
|
+
|
|
3966
3993
|
t.test('content-length in head route should not return zero when using wildcard', t => {
|
|
3967
3994
|
t.plan(6)
|
|
3968
3995
|
|
package/test/static2/bar.html
CHANGED
|
File without changes
|
package/test/static2/index.html
CHANGED
|
File without changes
|
package/tsconfig.eslint.json
CHANGED
|
File without changes
|
package/types/index.d.ts
CHANGED
|
File without changes
|
package/types/index.test-d.ts
CHANGED
|
File without changes
|