diff --git a/README.md b/README.md index 27450c5..5408d40 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,7 @@ The following options are also supported and will be passed directly to the [`@fastify/send`](https://www.npmjs.com/package/@fastify/send) module: - [`acceptRanges`](https://www.npmjs.com/package/@fastify/send#acceptranges) +- [`contentType`](https://www.npmjs.com/package/@fastify/send#contenttype) - [`cacheControl`](https://www.npmjs.com/package/@fastify/send#cachecontrol) (Enable or disable setting Cache-Control response header, defaults to true. **Important:** If you want to provide a custom Cache-Control response header, this option must be false.) - [`dotfiles`](https://www.npmjs.com/package/@fastify/send#dotfiles) - [`etag`](https://www.npmjs.com/package/@fastify/send#etag) diff --git a/index.js b/index.js index 119a50f..5b3e65e 100644 --- a/index.js +++ b/index.js @@ -38,6 +38,7 @@ async function fastifyStatic (fastify, opts) { const sendOptions = { root: opts.root, acceptRanges: opts.acceptRanges, + contentType: opts.contentType, cacheControl: opts.cacheControl, dotfiles: opts.dotfiles, etag: opts.etag, diff --git a/package.json b/package.json index 40969eb..8a16f92 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "homepage": "https://github.com/fastify/fastify-static", "dependencies": { "@fastify/accept-negotiator": "^2.0.0", - "@fastify/send": "^3.1.0", + "@fastify/send": "^3.2.0", "content-disposition": "^0.5.4", "fastify-plugin": "^5.0.0", "fastq": "^1.17.1", diff --git a/test/static.test.js b/test/static.test.js index 6089490..feab221 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -1377,10 +1377,11 @@ t.test('root not found warning', (t) => { }) t.test('send options', (t) => { - t.plan(11) + t.plan(12) const pluginOptions = { root: path.join(__dirname, '/static'), acceptRanges: 'acceptRanges', + contentType: 'contentType', cacheControl: 'cacheControl', dotfiles: 'dotfiles', etag: 'etag', @@ -1396,6 +1397,7 @@ t.test('send options', (t) => { t.equal(pathName, '/index.html') t.equal(options.root, path.join(__dirname, '/static')) t.equal(options.acceptRanges, 'acceptRanges') + t.equal(options.contentType, 'contentType') t.equal(options.cacheControl, 'cacheControl') t.equal(options.dotfiles, 'dotfiles') t.equal(options.etag, 'etag') @@ -4061,3 +4063,42 @@ t.test('respect the .code when using with sendFile', t => { }) }) }) + +t.test('respect the .type when using with sendFile with contentType disabled', t => { + t.plan(6) + + const pluginOptions = { + root: path.join(__dirname, '/static'), + contentType: false + } + const fastify = Fastify() + + fastify.register(fastifyStatic, pluginOptions) + + fastify.get('/custom', (_, reply) => { + return reply.type('text/html; charset=windows-1252').sendFile('foo.html') + }) + + t.teardown(fastify.close.bind(fastify)) + + fastify.listen({ port: 0 }, err => { + t.error(err) + + fastify.server.unref() + + const file = fs.readFileSync(path.join(__dirname, '/static/foo.html')) + const contentLength = Buffer.byteLength(file).toString() + + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/custom', + followRedirect: false + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 200) + t.equal(response.headers['content-type'], 'text/html; charset=windows-1252') + t.equal(response.headers['content-length'], contentLength) + t.equal(body.toString(), fooContent) + }) + }) +}) diff --git a/types/index.d.ts b/types/index.d.ts index 1af2a6b..e1d38f0 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -72,6 +72,7 @@ declare namespace fastifyStatic { // Passed on to `send` export interface SendOptions { acceptRanges?: boolean; + contentType?: boolean; cacheControl?: boolean; dotfiles?: 'allow' | 'deny' | 'ignore'; etag?: boolean; @@ -103,6 +104,7 @@ declare namespace fastifyStatic { // Passed on to `send` acceptRanges?: boolean; + contentType?: boolean; cacheControl?: boolean; dotfiles?: 'allow' | 'deny' | 'ignore'; etag?: boolean; diff --git a/types/index.test-d.ts b/types/index.test-d.ts index 0e63974..1812001 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -34,6 +34,7 @@ expectType(fastifyStaticCjs) const appWithImplicitHttp = fastify() const options: FastifyStaticOptions = { acceptRanges: true, + contentType: true, cacheControl: true, decorateReply: true, dotfiles: 'allow', @@ -145,6 +146,10 @@ appWithHttp2 appWithHttp2.get('/download/2', (request, reply) => { reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true }) }) + + appWithHttp2.get('/download/3', (request, reply) => { + reply.download('some-file-name', 'some-filename', { contentType: false }) + }) }) const multiRootAppWithImplicitHttp = fastify() @@ -165,6 +170,10 @@ multiRootAppWithImplicitHttp reply.sendFile('some-file-name', 'some-root-name', { cacheControl: false, acceptRanges: true }) }) + multiRootAppWithImplicitHttp.get('/', (request, reply) => { + reply.sendFile('some-file-name', 'some-root-name-2', { contentType: false }) + }) + multiRootAppWithImplicitHttp.get('/download', (request, reply) => { reply.download('some-file-name') }) @@ -176,6 +185,10 @@ multiRootAppWithImplicitHttp multiRootAppWithImplicitHttp.get('/download/2', (request, reply) => { reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true }) }) + + multiRootAppWithImplicitHttp.get('/download/3', (request, reply) => { + reply.download('some-file-name', 'some-filename', { contentType: false }) + }) }) const noIndexApp = fastify()