@fastify/static 8.0.1 → 8.0.3

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.
@@ -17,7 +17,7 @@ on:
17
17
 
18
18
  jobs:
19
19
  test:
20
- uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5.0.0
20
+ uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5
21
21
  with:
22
22
  license-check: true
23
23
  lint: true
package/README.md CHANGED
@@ -153,17 +153,18 @@ where the arguments are:
153
153
  #### `send` Options
154
154
 
155
155
  The following options are also supported and will be passed directly to the
156
- [`send`](https://www.npmjs.com/package/send) module:
157
-
158
- - [`acceptRanges`](https://www.npmjs.com/package/send#acceptranges)
159
- - [`cacheControl`](https://www.npmjs.com/package/send#cachecontrol)
160
- - [`dotfiles`](https://www.npmjs.com/package/send#dotfiles)
161
- - [`etag`](https://www.npmjs.com/package/send#etag)
162
- - [`extensions`](https://www.npmjs.com/package/send#extensions)
163
- - [`immutable`](https://www.npmjs.com/package/send#immutable)
164
- - [`index`](https://www.npmjs.com/package/send#index)
165
- - [`lastModified`](https://www.npmjs.com/package/send#lastmodified)
166
- - [`maxAge`](https://www.npmjs.com/package/send#maxage)
156
+ [`@fastify/send`](https://www.npmjs.com/package/@fastify/send) module:
157
+
158
+ - [`acceptRanges`](https://www.npmjs.com/package/@fastify/send#acceptranges)
159
+ - [`contentType`](https://www.npmjs.com/package/@fastify/send#contenttype)
160
+ - [`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.)
161
+ - [`dotfiles`](https://www.npmjs.com/package/@fastify/send#dotfiles)
162
+ - [`etag`](https://www.npmjs.com/package/@fastify/send#etag)
163
+ - [`extensions`](https://www.npmjs.com/package/@fastify/send#extensions)
164
+ - [`immutable`](https://www.npmjs.com/package/@fastify/send#immutable)
165
+ - [`index`](https://www.npmjs.com/package/@fastify/send#index)
166
+ - [`lastModified`](https://www.npmjs.com/package/@fastify/send#lastmodified)
167
+ - [`maxAge`](https://www.npmjs.com/package/@fastify/send#maxage)
167
168
 
168
169
  You're able to alter this options when calling `reply.download('filename.html', options)` or `reply.download('filename.html', 'otherfilename.html', options)` on each response to a request.
169
170
 
@@ -198,7 +199,7 @@ with `ignoreTrailingSlash` set to `true`.
198
199
 
199
200
  Default: `(pathName, root, request) => true`
200
201
 
201
- This function allows filtering the served files. Also, with the help of the request object a more complex path authentication is possible.
202
+ This function allows filtering the served files. Also, with the help of the request object a more complex path authentication is possible.
202
203
  If the function returns `true`, the file will be served.
203
204
  If the function returns `false`, Fastify's 404 handler will be called.
204
205
 
@@ -206,7 +207,7 @@ If the function returns `false`, Fastify's 404 handler will be called.
206
207
 
207
208
  Default: `undefined`
208
209
 
209
- Under the hood we use [send](https://github.com/pillarjs/send#index) lib that by default supports "index.html" files.
210
+ Under the hood we use [send](https://github.com/pillarjs/send#index) lib that by default supports "index.html" files.
210
211
  To disable this set false or to supply a new index pass a string or an array in preferred order.
211
212
 
212
213
  #### `serveDotFiles`
@@ -469,7 +470,7 @@ app.register((childContext, _, done) => {
469
470
  }, { prefix: 'docs' });
470
471
  ```
471
472
 
472
- This code will send the `index.html` for the paths `docs`, `docs/`, and `docs/index.html`. For all other `docs/<undefined-routes>` it will reply with `404.html`.
473
+ This code will send the `index.html` for the paths `docs`, `docs/`, and `docs/index.html`. For all other `docs/<undefined-routes>` it will reply with `404.html`.
473
474
 
474
475
  ### Handling Errors
475
476
 
package/index.js CHANGED
@@ -38,6 +38,7 @@ async function fastifyStatic (fastify, opts) {
38
38
  const sendOptions = {
39
39
  root: opts.root,
40
40
  acceptRanges: opts.acceptRanges,
41
+ contentType: opts.contentType,
41
42
  cacheControl: opts.cacheControl,
42
43
  dotfiles: opts.dotfiles,
43
44
  etag: opts.etag,
@@ -350,7 +351,11 @@ async function fastifyStatic (fastify, opts) {
350
351
  break
351
352
  }
352
353
  case 'file': {
353
- reply.code(statusCode)
354
+ // reply.raw.statusCode by default 200
355
+ // when ever the user changed it, we respect the status code
356
+ // otherwise use send provided status code
357
+ const newStatusCode = reply.statusCode !== 200 ? reply.statusCode : statusCode
358
+ reply.code(newStatusCode)
354
359
  if (setHeaders !== undefined) {
355
360
  setHeaders(reply.raw, metadata.path, metadata.stat)
356
361
  }
@@ -468,7 +473,7 @@ function getContentType (path) {
468
473
  if (!send.isUtf8MimeType(type)) {
469
474
  return type
470
475
  }
471
- return `${type}; charset=UTF-8`
476
+ return `${type}; charset=utf-8`
472
477
  }
473
478
 
474
479
  function findIndexFile (pathname, root, indexFiles = ['index.html']) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastify/static",
3
- "version": "8.0.1",
3
+ "version": "8.0.3",
4
4
  "description": "Plugin for serving static files as fast as possible.",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
@@ -30,7 +30,7 @@
30
30
  "homepage": "https://github.com/fastify/fastify-static",
31
31
  "dependencies": {
32
32
  "@fastify/accept-negotiator": "^2.0.0",
33
- "@fastify/send": "^3.1.0",
33
+ "@fastify/send": "^3.2.0",
34
34
  "content-disposition": "^0.5.4",
35
35
  "fastify-plugin": "^5.0.0",
36
36
  "fastq": "^1.17.1",
@@ -42,7 +42,7 @@
42
42
  "@types/node": "^22.0.0",
43
43
  "concat-stream": "^2.0.0",
44
44
  "eslint": "^9.9.0",
45
- "fastify": "^5.0.0",
45
+ "fastify": "^5.1.0",
46
46
  "neostandard": "^0.11.3",
47
47
  "pino": "^9.1.0",
48
48
  "proxyquire": "^2.1.3",
@@ -33,7 +33,7 @@ test('register /content-type', t => {
33
33
  url: 'http://localhost:' + fastify.server.address().port + '/content-type/index.html'
34
34
  }, (err, response) => {
35
35
  t.error(err)
36
- t.equal(response.headers['content-type'], 'text/html; charset=UTF-8')
36
+ t.equal(response.headers['content-type'], 'text/html; charset=utf-8')
37
37
  })
38
38
  })
39
39
 
@@ -44,7 +44,7 @@ test('register /content-type', t => {
44
44
  url: 'http://localhost:' + fastify.server.address().port + '/content-type/index.css'
45
45
  }, (err, response) => {
46
46
  t.error(err)
47
- t.equal(response.headers['content-type'], 'text/css; charset=UTF-8')
47
+ t.equal(response.headers['content-type'], 'text/css; charset=utf-8')
48
48
  })
49
49
  })
50
50
 
@@ -66,7 +66,7 @@ test('register /content-type', t => {
66
66
  url: 'http://localhost:' + fastify.server.address().port + '/content-type/test.txt'
67
67
  }, (err, response) => {
68
68
  t.error(err)
69
- t.equal(response.headers['content-type'], 'text/plain; charset=UTF-8')
69
+ t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
70
70
  })
71
71
  })
72
72
 
@@ -111,7 +111,7 @@ test('register /content-type preCompressed', t => {
111
111
  }
112
112
  }, (err, response) => {
113
113
  t.error(err)
114
- t.equal(response.headers['content-type'], 'text/html; charset=UTF-8')
114
+ t.equal(response.headers['content-type'], 'text/html; charset=utf-8')
115
115
  })
116
116
  })
117
117
 
@@ -125,7 +125,7 @@ test('register /content-type preCompressed', t => {
125
125
  }
126
126
  }, (err, response) => {
127
127
  t.error(err)
128
- t.equal(response.headers['content-type'], 'text/css; charset=UTF-8')
128
+ t.equal(response.headers['content-type'], 'text/css; charset=utf-8')
129
129
  })
130
130
  })
131
131
 
@@ -153,7 +153,7 @@ test('register /content-type preCompressed', t => {
153
153
  }
154
154
  }, (err, response) => {
155
155
  t.error(err)
156
- t.equal(response.headers['content-type'], 'text/plain; charset=UTF-8')
156
+ t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
157
157
  })
158
158
  })
159
159
 
@@ -0,0 +1 @@
1
+ /none
@@ -0,0 +1 @@
1
+ ../origin
@@ -1377,10 +1377,11 @@ t.test('root not found warning', (t) => {
1377
1377
  })
1378
1378
 
1379
1379
  t.test('send options', (t) => {
1380
- t.plan(11)
1380
+ t.plan(12)
1381
1381
  const pluginOptions = {
1382
1382
  root: path.join(__dirname, '/static'),
1383
1383
  acceptRanges: 'acceptRanges',
1384
+ contentType: 'contentType',
1384
1385
  cacheControl: 'cacheControl',
1385
1386
  dotfiles: 'dotfiles',
1386
1387
  etag: 'etag',
@@ -1396,6 +1397,7 @@ t.test('send options', (t) => {
1396
1397
  t.equal(pathName, '/index.html')
1397
1398
  t.equal(options.root, path.join(__dirname, '/static'))
1398
1399
  t.equal(options.acceptRanges, 'acceptRanges')
1400
+ t.equal(options.contentType, 'contentType')
1399
1401
  t.equal(options.cacheControl, 'cacheControl')
1400
1402
  t.equal(options.dotfiles, 'dotfiles')
1401
1403
  t.equal(options.etag, 'etag')
@@ -4017,9 +4019,86 @@ t.test('content-length in head route should not return zero when using wildcard'
4017
4019
  }, (err, response, body) => {
4018
4020
  t.error(err)
4019
4021
  t.equal(response.statusCode, 200)
4020
- t.equal(response.headers['content-type'], 'text/html; charset=UTF-8')
4022
+ t.equal(response.headers['content-type'], 'text/html; charset=utf-8')
4021
4023
  t.equal(response.headers['content-length'], contentLength)
4022
4024
  t.equal(body.toString(), '')
4023
4025
  })
4024
4026
  })
4025
4027
  })
4028
+
4029
+ t.test('respect the .code when using with sendFile', t => {
4030
+ t.plan(6)
4031
+
4032
+ const pluginOptions = {
4033
+ root: path.join(__dirname, '/static')
4034
+ }
4035
+ const fastify = Fastify()
4036
+
4037
+ fastify.register(fastifyStatic, pluginOptions)
4038
+
4039
+ fastify.get('/custom', (_, reply) => {
4040
+ return reply.code(404).type('text/html').sendFile('foo.html')
4041
+ })
4042
+
4043
+ t.teardown(fastify.close.bind(fastify))
4044
+
4045
+ fastify.listen({ port: 0 }, err => {
4046
+ t.error(err)
4047
+
4048
+ fastify.server.unref()
4049
+
4050
+ const file = fs.readFileSync(path.join(__dirname, '/static/foo.html'))
4051
+ const contentLength = Buffer.byteLength(file).toString()
4052
+
4053
+ simple.concat({
4054
+ method: 'HEAD',
4055
+ url: 'http://localhost:' + fastify.server.address().port + '/custom',
4056
+ followRedirect: false
4057
+ }, (err, response, body) => {
4058
+ t.error(err)
4059
+ t.equal(response.statusCode, 404)
4060
+ t.equal(response.headers['content-type'], 'text/html; charset=utf-8')
4061
+ t.equal(response.headers['content-length'], contentLength)
4062
+ t.equal(body.toString(), '')
4063
+ })
4064
+ })
4065
+ })
4066
+
4067
+ t.test('respect the .type when using with sendFile with contentType disabled', t => {
4068
+ t.plan(6)
4069
+
4070
+ const pluginOptions = {
4071
+ root: path.join(__dirname, '/static'),
4072
+ contentType: false
4073
+ }
4074
+ const fastify = Fastify()
4075
+
4076
+ fastify.register(fastifyStatic, pluginOptions)
4077
+
4078
+ fastify.get('/custom', (_, reply) => {
4079
+ return reply.type('text/html; charset=windows-1252').sendFile('foo.html')
4080
+ })
4081
+
4082
+ t.teardown(fastify.close.bind(fastify))
4083
+
4084
+ fastify.listen({ port: 0 }, err => {
4085
+ t.error(err)
4086
+
4087
+ fastify.server.unref()
4088
+
4089
+ const file = fs.readFileSync(path.join(__dirname, '/static/foo.html'))
4090
+ const contentLength = Buffer.byteLength(file).toString()
4091
+
4092
+ simple.concat({
4093
+ method: 'GET',
4094
+ url: 'http://localhost:' + fastify.server.address().port + '/custom',
4095
+ followRedirect: false
4096
+ }, (err, response, body) => {
4097
+ t.error(err)
4098
+ t.equal(response.statusCode, 200)
4099
+ t.equal(response.headers['content-type'], 'text/html; charset=windows-1252')
4100
+ t.equal(response.headers['content-length'], contentLength)
4101
+ t.equal(body.toString(), fooContent)
4102
+ })
4103
+ })
4104
+ })
package/types/index.d.ts CHANGED
@@ -72,6 +72,7 @@ declare namespace fastifyStatic {
72
72
  // Passed on to `send`
73
73
  export interface SendOptions {
74
74
  acceptRanges?: boolean;
75
+ contentType?: boolean;
75
76
  cacheControl?: boolean;
76
77
  dotfiles?: 'allow' | 'deny' | 'ignore';
77
78
  etag?: boolean;
@@ -103,6 +104,7 @@ declare namespace fastifyStatic {
103
104
 
104
105
  // Passed on to `send`
105
106
  acceptRanges?: boolean;
107
+ contentType?: boolean;
106
108
  cacheControl?: boolean;
107
109
  dotfiles?: 'allow' | 'deny' | 'ignore';
108
110
  etag?: boolean;
@@ -13,13 +13,13 @@ const fastifyStaticCjs = require('..')
13
13
 
14
14
  const app: FastifyInstance = fastify()
15
15
 
16
- app.register(fastifyStatic)
17
- app.register(fastifyStaticNamed)
18
- app.register(fastifyStaticCjs)
19
- app.register(fastifyStaticCjsImport.default)
20
- app.register(fastifyStaticCjsImport.fastifyStatic)
21
- app.register(fastifyStaticStar.default)
22
- app.register(fastifyStaticStar.fastifyStatic)
16
+ app.register(fastifyStatic, { root: __dirname })
17
+ app.register(fastifyStaticNamed, { root: __dirname })
18
+ app.register(fastifyStaticCjs, { root: __dirname })
19
+ app.register(fastifyStaticCjsImport.default, { root: __dirname })
20
+ app.register(fastifyStaticCjsImport.fastifyStatic, { root: __dirname })
21
+ app.register(fastifyStaticStar.default, { root: __dirname })
22
+ app.register(fastifyStaticStar.fastifyStatic, { root: __dirname })
23
23
 
24
24
  expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStatic)
25
25
  expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStaticNamed)
@@ -34,6 +34,7 @@ expectType<any>(fastifyStaticCjs)
34
34
  const appWithImplicitHttp = fastify()
35
35
  const options: FastifyStaticOptions = {
36
36
  acceptRanges: true,
37
+ contentType: true,
37
38
  cacheControl: true,
38
39
  decorateReply: true,
39
40
  dotfiles: 'allow',
@@ -145,6 +146,10 @@ appWithHttp2
145
146
  appWithHttp2.get('/download/2', (request, reply) => {
146
147
  reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true })
147
148
  })
149
+
150
+ appWithHttp2.get('/download/3', (request, reply) => {
151
+ reply.download('some-file-name', 'some-filename', { contentType: false })
152
+ })
148
153
  })
149
154
 
150
155
  const multiRootAppWithImplicitHttp = fastify()
@@ -165,6 +170,10 @@ multiRootAppWithImplicitHttp
165
170
  reply.sendFile('some-file-name', 'some-root-name', { cacheControl: false, acceptRanges: true })
166
171
  })
167
172
 
173
+ multiRootAppWithImplicitHttp.get('/', (request, reply) => {
174
+ reply.sendFile('some-file-name', 'some-root-name-2', { contentType: false })
175
+ })
176
+
168
177
  multiRootAppWithImplicitHttp.get('/download', (request, reply) => {
169
178
  reply.download('some-file-name')
170
179
  })
@@ -176,6 +185,10 @@ multiRootAppWithImplicitHttp
176
185
  multiRootAppWithImplicitHttp.get('/download/2', (request, reply) => {
177
186
  reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true })
178
187
  })
188
+
189
+ multiRootAppWithImplicitHttp.get('/download/3', (request, reply) => {
190
+ reply.download('some-file-name', 'some-filename', { contentType: false })
191
+ })
179
192
  })
180
193
 
181
194
  const noIndexApp = fastify()