|
4 | 4 |
|
5 | 5 | const fs = require('node:fs') |
6 | 6 | const http = require('node:http') |
| 7 | +const os = require('node:os') |
7 | 8 | const path = require('node:path') |
8 | 9 | const { test } = require('node:test') |
9 | 10 | const Fastify = require('fastify') |
@@ -369,6 +370,63 @@ test('dir list href nested structure', async t => { |
369 | 370 | }) |
370 | 371 | }) |
371 | 372 |
|
| 373 | +test('dir list html format - href encodes # and ? in file and directory names', async t => { |
| 374 | + const root = fs.mkdtempSync(path.join(os.tmpdir(), 'fastify-static-dir-list-hash-')) |
| 375 | + t.after(() => fs.rmSync(root, { recursive: true, force: true })) |
| 376 | + // `?` is not allowed in Windows file names |
| 377 | + const posix = process.platform !== 'win32' |
| 378 | + const files = { 'a#b.txt': '/public/a%23b.txt' } |
| 379 | + if (posix) { |
| 380 | + files['a?b.txt'] = '/public/a%3Fb.txt' |
| 381 | + } |
| 382 | + const dir = posix ? 'd#?x' : 'd#x' |
| 383 | + const dirHref = posix ? '/public/d%23%3Fx' : '/public/d%23x' |
| 384 | + for (const name of Object.keys(files)) { |
| 385 | + fs.writeFileSync(path.join(root, name), name) |
| 386 | + } |
| 387 | + fs.mkdirSync(path.join(root, dir)) |
| 388 | + fs.writeFileSync(path.join(root, dir, 'c#d.txt'), 'nested') |
| 389 | + |
| 390 | + const options = { |
| 391 | + root, |
| 392 | + prefix: '/public', |
| 393 | + index: false, |
| 394 | + list: { |
| 395 | + format: 'html', |
| 396 | + names: ['index'], |
| 397 | + render (dirs, files) { |
| 398 | + return JSON.stringify({ |
| 399 | + dirs: dirs.map(entry => entry.href), |
| 400 | + files: files.map(entry => entry.href).sort() |
| 401 | + }) |
| 402 | + } |
| 403 | + } |
| 404 | + } |
| 405 | + |
| 406 | + await helper.arrange(t, options, async (url) => { |
| 407 | + const response = await fetch(url + '/public/index') |
| 408 | + t.assert.deepStrictEqual(response.status, 200) |
| 409 | + const listing = JSON.parse(await response.text()) |
| 410 | + t.assert.deepStrictEqual(listing.dirs, [dirHref]) |
| 411 | + t.assert.deepStrictEqual(listing.files, Object.values(files).sort()) |
| 412 | + |
| 413 | + for (const [name, href] of Object.entries(files)) { |
| 414 | + const file = await fetch(url + href) |
| 415 | + t.assert.deepStrictEqual(file.status, 200) |
| 416 | + t.assert.deepStrictEqual(await file.text(), name) |
| 417 | + } |
| 418 | + |
| 419 | + const nested = await fetch(url + dirHref + '/index') |
| 420 | + t.assert.deepStrictEqual(nested.status, 200) |
| 421 | + const nestedListing = JSON.parse(await nested.text()) |
| 422 | + t.assert.deepStrictEqual(nestedListing.files, [dirHref + '/c%23d.txt']) |
| 423 | + |
| 424 | + const file = await fetch(url + nestedListing.files[0]) |
| 425 | + t.assert.deepStrictEqual(file.status, 200) |
| 426 | + t.assert.deepStrictEqual(await file.text(), 'nested') |
| 427 | + }) |
| 428 | +}) |
| 429 | + |
372 | 430 | test('dir list html format - stats', async t => { |
373 | 431 | t.plan(6) |
374 | 432 |
|
|
0 commit comments