fastify 3.20.1 → 3.20.2

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/docs/Ecosystem.md CHANGED
@@ -44,6 +44,7 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
44
44
  - [`fastify-routes`](https://github.com/fastify/fastify-routes) Plugin that provides a `Map` of routes.
45
45
  - [`fastify-schedule`](https://github.com/fastify/fastify-schedule) Plugin for scheduling periodic jobs, based on [toad-scheduler](https://github.com/kibertoad/toad-scheduler).
46
46
  - [`fastify-sensible`](https://github.com/fastify/fastify-sensible) Defaults for Fastify that everyone can agree on. It adds some useful decorators such as HTTP errors and assertions, but also more request and reply methods.
47
+ - [`@fastify/session`](https://github.com/fastify/session) a session plugin for Fastify.
47
48
  - [`fastify-static`](https://github.com/fastify/fastify-static) Plugin for serving static files as fast as possible.
48
49
  - [`fastify-swagger`](https://github.com/fastify/fastify-swagger) Plugin for serving Swagger/OpenAPI documentation for Fastify, supporting dynamic generation.
49
50
  - [`fastify-websocket`](https://github.com/fastify/fastify-websocket) WebSocket support for Fastify. Built upon [websocket-stream](https://github.com/maxogden/websocket-stream).
@@ -69,6 +70,7 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
69
70
  - [`arecibo`](https://github.com/nucleode/arecibo) Fastify ping responder for Kubernetes Liveness and Readiness Probes.
70
71
  - [`cls-rtracer`](https://github.com/puzpuzpuz/cls-rtracer) Fastify middleware for CLS-based request ID generation. An out-of-the-box solution for adding request IDs into your logs.
71
72
  - [`fastify-405`](https://github.com/Eomm/fastify-405) Fastify plugin that adds 405 HTTP status to your routes
73
+ - [`fastify-allow`](https://github.com/mattbishop/fastify-allow) Fastify plugin that automatically adds an Allow header to responses with routes. Also sends 405 responses for routes that have a handler but not for the request's method.
72
74
  - [`fastify-amqp`](https://github.com/RafaelGSS/fastify-amqp) Fastify AMQP connection plugin, to use with RabbitMQ or another connector. Just a wrapper to [`amqplib`](https://github.com/squaremo/amqp.node).
73
75
  - [`fastify-angular-universal`](https://github.com/exequiel09/fastify-angular-universal) Angular server-side rendering support using [`@angular/platform-server`](https://github.com/angular/angular/tree/master/packages/platform-server) for Fastify
74
76
  - [`fastify-api-key`](https://github.com/arkerone/fastify-api-key) Fastify plugin to authenticate HTTP requests based on api key and signature
@@ -177,7 +179,6 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
177
179
  - [`fastify-sentry`](https://github.com/alex-ppg/fastify-sentry) Fastify plugin to add the Sentry SDK error handler to requests.
178
180
  - [`fastify-sequelize`](https://github.com/lyquocnam/fastify-sequelize) Fastify plugin work with Sequelize (adapter for NodeJS -> Sqlite, Mysql, Mssql, Postgres).
179
181
  - [`fastify-server-session`](https://github.com/jsumners/fastify-server-session) A session plugin with support for arbitrary backing caches via `fastify-caching`.
180
- - [`fastify-session`](https://github.com/SerayaEryn/fastify-session) a session plugin for Fastify.
181
182
  - [`fastify-slonik`](https://github.com/Unbuttun/fastify-slonik) Fastify Slonik plugin, with this you can use slonik in every part of your server.
182
183
  - [`fastify-soap-client`](https://github.com/fastify/fastify-soap-client) a SOAP client plugin for Fastify.
183
184
  - [`fastify-socket.io`](https://github.com/alemagio/fastify-socket.io) a Socket.io plugin for Fastify.
@@ -200,7 +200,7 @@ As you can see, we used `register` for both the database connector and the regis
200
200
  This is one of the best features of Fastify, it will load your plugins in the same order you declare them, and it will load the next plugin only once the current one has been loaded. In this way, we can register the database connector in the first plugin and use it in the second *(read [here](Plugins.md#handle-the-scope) to understand how to handle the scope of a plugin)*.
201
201
  Plugin loading starts when you call `fastify.listen()`, `fastify.inject()` or `fastify.ready()`
202
202
 
203
- We have also used the `decorate` API to add custom objects to the Fastify namespace, making them available for use everywhere. Use of this API is encouraged to facilitate easy code reuse and to decrease code or logic duplication.
203
+ The MongoDB plugin uses the `decorate` API to add custom objects to the Fastify instance, making them available for use everywhere. Use of this API is encouraged to facilitate easy code reuse and to decrease code or logic duplication.
204
204
 
205
205
  To dig deeper into how Fastify plugins work, how to develop new plugins, and for details on how to use the whole Fastify API to deal with the complexity of asynchronously bootstrapping an application, read [the hitchhiker's guide to plugins](Plugins-Guide.md).
206
206
 
package/docs/Request.md CHANGED
@@ -6,7 +6,7 @@ Request is a core Fastify object containing the following fields:
6
6
  - `query` - the parsed querystring
7
7
  - `body` - the body
8
8
  - `params` - the params matching the URL
9
- - `headers` - the headers
9
+ - [`headers`](#headers) - the headers getter and setter
10
10
  - `raw` - the incoming HTTP request from Node core
11
11
  - `req` *(deprecated, use `.raw` instead)* - the incoming HTTP request from Node core
12
12
  - `server` - The Fastify server instance, scoped to the current [encapsulation context](Encapsulation.md)
@@ -26,6 +26,20 @@ Request is a core Fastify object containing the following fields:
26
26
  - `context` - A Fastify internal object. You should not use it directly or modify it. It is usefull to access one special key:
27
27
  - `context.config` - The route [`config`](Routes.md#routes-config) object.
28
28
 
29
+ ### Headers
30
+
31
+ The `request.headers` is a getter that return an Object with the headers of the incoming request.
32
+ You can set custom headers like this:
33
+
34
+ ```js
35
+ request.headers = {
36
+ 'foo': 'bar',
37
+ 'baz': 'qux'
38
+ }
39
+ ```
40
+
41
+ This operation will add to the request headers the new values that can be read calling `request.headers.bar`.
42
+ Moreover, you can still access the standard request's headers with the `request.raw.headers` property.
29
43
 
30
44
  ```js
31
45
  fastify.post('/:params', options, function (request, reply) {
@@ -40,6 +54,9 @@ fastify.post('/:params', options, function (request, reply) {
40
54
  console.log(request.ips)
41
55
  console.log(request.hostname)
42
56
  console.log(request.protocol)
57
+ console.log(request.url)
58
+ console.log(request.routerMethod)
59
+ console.log(request.routerPath)
43
60
  request.log.info('some info')
44
61
  })
45
62
  ```
@@ -85,7 +85,7 @@ The type system heavily relies on generic properties to provide the most accurat
85
85
  'h-Custom': string;
86
86
  }
87
87
  ```
88
- 3. Using the two interfaces, define a new API route and pass them as generics. The shorthand route methods (i.e. `.get`) accept a generic object `RequestGenericInterface` containing four named properties: `Body`, `Querystring`, `Params`, and `Headers`. The interfaces will be passed down through the route method into the route method handler `request` instance.
88
+ 3. Using the two interfaces, define a new API route and pass them as generics. The shorthand route methods (i.e. `.get`) accept a generic object `RouteGenericInterface` containing five named properties: `Body`, `Querystring`, `Params`, `Headers` and `Reply`. The interfaces `Body`, `Querystring`, `Params` and `Headers` will be passed down through the route method into the route method handler `request` instance and the `Reply` interface to the `reply` instance.
89
89
  ```typescript
90
90
  server.get<{
91
91
  Querystring: IQuerystring,
@@ -599,7 +599,7 @@ The Fastify API is powered by the `fastify()` method. In JavaScript you would im
599
599
  const f = fastify()
600
600
  f.listen(8080, () => { console.log('running') })
601
601
  ```
602
- - Destructuring is still supported, but will also not resolve types
602
+ - Destructuring is supported and will resolve types properly
603
603
  ```typescript
604
604
  const { fastify } = require('fastify')
605
605
 
package/fastify.js CHANGED
@@ -541,9 +541,8 @@ function fastify (options) {
541
541
 
542
542
  function defaultClientErrorHandler (err, socket) {
543
543
  // In case of a connection reset, the socket has been destroyed and there is nothing that needs to be done.
544
- // https://github.com/fastify/fastify/issues/2036
545
- // https://github.com/nodejs/node/issues/33302
546
- if (err.code === 'ECONNRESET') {
544
+ // https://nodejs.org/api/http.html#http_event_clienterror
545
+ if (err.code === 'ECONNRESET' || socket.destroyed) {
547
546
  return
548
547
  }
549
548
 
@@ -557,11 +556,14 @@ function fastify (options) {
557
556
  // In the vast majority of cases, it's a network error and/or some
558
557
  // config issue on the load balancer side.
559
558
  this.log.trace({ err }, 'client error')
559
+ // Copying standard node behaviour
560
+ // https://github.com/nodejs/node/blob/6ca23d7846cb47e84fd344543e394e50938540be/lib/_http_server.js#L666
560
561
 
561
562
  // If the socket is not writable, there is no reason to try to send data.
562
- if (socket.writable) {
563
- socket.end(`HTTP/1.1 400 Bad Request\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`)
563
+ if (socket.writable && socket.bytesWritten === 0) {
564
+ socket.write(`HTTP/1.1 400 Bad Request\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`)
564
565
  }
566
+ socket.destroy(err)
565
567
  }
566
568
 
567
569
  // If the router does not match any route, every request will land here
package/lib/request.js CHANGED
@@ -162,7 +162,13 @@ Object.defineProperties(Request.prototype, {
162
162
  },
163
163
  headers: {
164
164
  get () {
165
+ if (this.additionalHeaders) {
166
+ return Object.assign({}, this.raw.headers, this.additionalHeaders)
167
+ }
165
168
  return this.raw.headers
169
+ },
170
+ set (headers) {
171
+ this.additionalHeaders = headers
166
172
  }
167
173
  },
168
174
  server: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify",
3
- "version": "3.20.1",
3
+ "version": "3.20.2",
4
4
  "description": "Fast and low overhead web framework, for Node.js",
5
5
  "main": "fastify.js",
6
6
  "type": "commonjs",
@@ -127,6 +127,78 @@ test('default clientError handler ignores ECONNRESET', t => {
127
127
  })
128
128
  })
129
129
 
130
+ test('default clientError handler ignores sockets in destroyed state', t => {
131
+ t.plan(1)
132
+
133
+ const fastify = Fastify({
134
+ bodyLimit: 1,
135
+ keepAliveTimeout: 100,
136
+ logger: {
137
+ level: 'trace'
138
+ }
139
+ })
140
+ fastify.server.on('clientError', () => {
141
+ // this handler is called after default handler, so we can make sure end was not called
142
+ t.pass()
143
+ })
144
+ fastify.server.emit('clientError', new Error(), {
145
+ destroyed: true,
146
+ end () {
147
+ t.fail('end should not be called')
148
+ },
149
+ destroy () {
150
+ t.fail('destroy should not be called')
151
+ }
152
+ })
153
+ })
154
+
155
+ test('default clientError handler destroys sockets in writable state', t => {
156
+ t.plan(1)
157
+
158
+ const fastify = Fastify({
159
+ bodyLimit: 1,
160
+ keepAliveTimeout: 100,
161
+ logger: {
162
+ level: 'trace'
163
+ }
164
+ })
165
+
166
+ fastify.server.emit('clientError', new Error(), {
167
+ destroyed: false,
168
+ writable: true,
169
+ encrypted: true,
170
+ end () {
171
+ t.fail('end should not be called')
172
+ },
173
+ destroy () {
174
+ t.pass('destroy should be called')
175
+ }
176
+ })
177
+ })
178
+
179
+ test('default clientError handler destroys http sockets in non-writable state', t => {
180
+ t.plan(1)
181
+
182
+ const fastify = Fastify({
183
+ bodyLimit: 1,
184
+ keepAliveTimeout: 100,
185
+ logger: {
186
+ level: 'trace'
187
+ }
188
+ })
189
+
190
+ fastify.server.emit('clientError', new Error(), {
191
+ destroyed: false,
192
+ writable: false,
193
+ end () {
194
+ t.fail('end should not be called')
195
+ },
196
+ destroy () {
197
+ t.pass('destroy should be called')
198
+ }
199
+ })
200
+ })
201
+
130
202
  test('error handler binding', t => {
131
203
  t.plan(5)
132
204
 
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { test } = require('tap')
4
+ const Joi = require('@hapi/joi')
4
5
  const AJV = require('ajv')
5
6
  const S = require('fluent-json-schema')
6
7
  const Fastify = require('..')
@@ -748,3 +749,34 @@ test('multiple refs with the same ids', t => {
748
749
  t.same(res.json(), { hello: 'world' })
749
750
  })
750
751
  })
752
+
753
+ test('JOI validation overwrite request headers', t => {
754
+ t.plan(3)
755
+ const schemaValidator = ({ schema }) => data => {
756
+ const validationResult = schema.validate(data)
757
+ return validationResult
758
+ }
759
+
760
+ const fastify = Fastify()
761
+ fastify.setValidatorCompiler(schemaValidator)
762
+
763
+ fastify.get('/', {
764
+ schema: {
765
+ headers: Joi.object({
766
+ 'user-agent': Joi.string().required(),
767
+ host: Joi.string().required()
768
+ })
769
+ }
770
+ }, (request, reply) => {
771
+ reply.send(request.headers)
772
+ })
773
+
774
+ fastify.inject('/', (err, res) => {
775
+ t.error(err)
776
+ t.equal(res.statusCode, 200)
777
+ t.same(res.json(), {
778
+ 'user-agent': 'lightMyRequest',
779
+ host: 'localhost:80'
780
+ })
781
+ })
782
+ })