fastify 4.22.0 → 4.22.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/Guides/Database.md +1 -1
- package/docs/Guides/Ecosystem.md +7 -1
- package/docs/Guides/Serverless.md +2 -2
- package/docs/Reference/Errors.md +1 -1
- package/docs/Reference/HTTP2.md +2 -1
- package/docs/Reference/Hooks.md +1 -1
- package/docs/Reference/Server.md +1 -1
- package/fastify.js +1 -1
- package/lib/contentTypeParser.js +2 -2
- package/lib/handleRequest.js +3 -3
- package/lib/hooks.js +7 -4
- package/lib/logger.js +1 -1
- package/lib/reply.js +19 -14
- package/lib/request.js +2 -2
- package/lib/schemas.js +1 -1
- package/lib/server.js +4 -4
- package/lib/validation.js +1 -1
- package/lib/wrapThenable.js +1 -4
- package/package.json +2 -2
- package/test/build/error-serializer.test.js +2 -2
- package/test/post-empty-body.test.js +31 -0
- package/test/wrapThenable.test.js +0 -22
package/docs/Guides/Database.md
CHANGED
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -46,7 +46,7 @@ section.
|
|
|
46
46
|
Plugin to deal with `diagnostics_channel` on Fastify
|
|
47
47
|
- [`@fastify/early-hints`](https://github.com/fastify/fastify-early-hints) Plugin
|
|
48
48
|
to add HTTP 103 feature based on [RFC
|
|
49
|
-
8297](https://
|
|
49
|
+
8297](https://datatracker.ietf.org/doc/html/rfc8297).
|
|
50
50
|
- [`@fastify/elasticsearch`](https://github.com/fastify/fastify-elasticsearch)
|
|
51
51
|
Plugin to share the same ES client.
|
|
52
52
|
- [`@fastify/env`](https://github.com/fastify/fastify-env) Load and check
|
|
@@ -121,6 +121,8 @@ section.
|
|
|
121
121
|
- [`@fastify/swagger`](https://github.com/fastify/fastify-swagger) Plugin for
|
|
122
122
|
serving Swagger/OpenAPI documentation for Fastify, supporting dynamic
|
|
123
123
|
generation.
|
|
124
|
+
- [`@fastify/throttle`](https://github.com/fastify/fastify-throttle) Plugin for
|
|
125
|
+
- throttling the download speed of a request.
|
|
124
126
|
- [`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts)
|
|
125
127
|
Fastify
|
|
126
128
|
[type provider](https://www.fastify.io/docs/latest/Reference/Type-Providers/)
|
|
@@ -520,6 +522,10 @@ middlewares into Fastify plugins
|
|
|
520
522
|
- [`fastify-qs`](https://github.com/vanodevium/fastify-qs) A plugin for Fastify
|
|
521
523
|
that adds support for parsing URL query parameters with
|
|
522
524
|
[qs](https://github.com/ljharb/qs).
|
|
525
|
+
- [`fastify-rabbitmq`](https://github.com/Bugs5382/fastify-rabbitmq) Fastify
|
|
526
|
+
RabbitMQ plugin that uses
|
|
527
|
+
[node-amqp-connection-manager](https://github.com/jwalton/node-amqp-connection-manager)
|
|
528
|
+
plugin as a wrapper.
|
|
523
529
|
- [`fastify-racing`](https://github.com/metcoder95/fastify-racing) Fastify's
|
|
524
530
|
plugin that adds support to handle an aborted request asynchronous.
|
|
525
531
|
- [`fastify-ravendb`](https://github.com/nearform/fastify-ravendb) RavenDB
|
|
@@ -487,10 +487,10 @@ with your GitHub account.
|
|
|
487
487
|
Create your first application and a static workspace: be careful to download the
|
|
488
488
|
API key as an env file, e.g. `yourworkspace.txt`.
|
|
489
489
|
|
|
490
|
-
Then, you can easily deploy your application with the following
|
|
490
|
+
Then, you can easily deploy your application with the following command:
|
|
491
491
|
|
|
492
492
|
```bash
|
|
493
|
-
platformatic deploy --keys `
|
|
493
|
+
platformatic deploy --keys `yourworkspace.txt`
|
|
494
494
|
```
|
|
495
495
|
|
|
496
496
|
Check out the [Full Guide](https://blog.platformatic.dev/how-to-migrate-a-fastify-app-to-platformatic-service)
|
package/docs/Reference/Errors.md
CHANGED
|
@@ -510,7 +510,7 @@ Impossible to load plugin because the parent (mapped directly from `avvio`)
|
|
|
510
510
|
#### FST_ERR_PLUGIN_TIMEOUT
|
|
511
511
|
<a id="FST_ERR_PLUGIN_TIMEOUT"></a>
|
|
512
512
|
|
|
513
|
-
Plugin did not start in time. Default timeout (in
|
|
513
|
+
Plugin did not start in time. Default timeout (in milliseconds): `10000`
|
|
514
514
|
|
|
515
515
|
#### FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE
|
|
516
516
|
<a id="FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE"></a>
|
package/docs/Reference/HTTP2.md
CHANGED
|
@@ -32,7 +32,8 @@ fastify.get('/', function (request, reply) {
|
|
|
32
32
|
fastify.listen({ port: 3000 })
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
ALPN negotiation allows
|
|
35
|
+
[ALPN negotiation](https://datatracker.ietf.org/doc/html/rfc7301) allows
|
|
36
|
+
support for both HTTPS and HTTP/2 over the same socket.
|
|
36
37
|
Node core `req` and `res` objects can be either
|
|
37
38
|
[HTTP/1](https://nodejs.org/api/http.html) or
|
|
38
39
|
[HTTP/2](https://nodejs.org/api/http2.html). _Fastify_ supports this out of the
|
package/docs/Reference/Hooks.md
CHANGED
|
@@ -80,7 +80,7 @@ hooks, and a stream with the current request payload.
|
|
|
80
80
|
If it returns a value (via `return` or via the callback function), it must
|
|
81
81
|
return a stream.
|
|
82
82
|
|
|
83
|
-
For instance, you can
|
|
83
|
+
For instance, you can decompress the request body:
|
|
84
84
|
|
|
85
85
|
```js
|
|
86
86
|
fastify.addHook('preParsing', (request, reply, payload, done) => {
|
package/docs/Reference/Server.md
CHANGED
|
@@ -480,7 +480,7 @@ is not equal to `/Foo`.
|
|
|
480
480
|
When `false` then routes are case-insensitive.
|
|
481
481
|
|
|
482
482
|
Please note that setting this option to `false` goes against
|
|
483
|
-
[RFC3986](https://
|
|
483
|
+
[RFC3986](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1).
|
|
484
484
|
|
|
485
485
|
By setting `caseSensitive` to `false`, all paths will be matched as lowercase,
|
|
486
486
|
but the route parameters or wildcards will maintain their original letter
|
package/fastify.js
CHANGED
package/lib/contentTypeParser.js
CHANGED
|
@@ -102,7 +102,7 @@ ContentTypeParser.prototype.getParser = function (contentType) {
|
|
|
102
102
|
const parsed = safeParseContentType(contentType)
|
|
103
103
|
|
|
104
104
|
// dummyContentType always the same object
|
|
105
|
-
// we can use === for the
|
|
105
|
+
// we can use === for the comparison and return early
|
|
106
106
|
if (parsed === defaultContentType) {
|
|
107
107
|
return this.customParsers.get('')
|
|
108
108
|
}
|
|
@@ -399,7 +399,7 @@ function compareRegExpContentType (contentType, essenceMIMEType, regexp) {
|
|
|
399
399
|
function ParserListItem (contentType) {
|
|
400
400
|
this.name = contentType
|
|
401
401
|
// we pre-calculate all the needed information
|
|
402
|
-
// before content-type
|
|
402
|
+
// before content-type comparison
|
|
403
403
|
const parsed = safeParseContentType(contentType)
|
|
404
404
|
this.isEssence = contentType.indexOf(';') === -1
|
|
405
405
|
// we should not allow empty string for parser list item
|
package/lib/handleRequest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { validate: validateSchema } = require('./validation')
|
|
4
|
-
const {
|
|
4
|
+
const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
|
|
5
5
|
const wrapThenable = require('./wrapThenable')
|
|
6
6
|
const {
|
|
7
7
|
kReplyIsError,
|
|
@@ -65,7 +65,7 @@ function handleRequest (err, request, reply) {
|
|
|
65
65
|
function handler (request, reply) {
|
|
66
66
|
try {
|
|
67
67
|
if (request[kRouteContext].preValidation !== null) {
|
|
68
|
-
|
|
68
|
+
preValidationHookRunner(
|
|
69
69
|
request[kRouteContext].preValidation,
|
|
70
70
|
request,
|
|
71
71
|
reply,
|
|
@@ -111,7 +111,7 @@ function validationCompleted (request, reply, validationErr) {
|
|
|
111
111
|
|
|
112
112
|
// preHandler hook
|
|
113
113
|
if (request[kRouteContext].preHandler !== null) {
|
|
114
|
-
|
|
114
|
+
preHandlerHookRunner(
|
|
115
115
|
request[kRouteContext].preHandler,
|
|
116
116
|
request,
|
|
117
117
|
reply,
|
package/lib/hooks.js
CHANGED
|
@@ -217,8 +217,8 @@ function onResponseHookIterator (fn, request, reply, next) {
|
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
const onResponseHookRunner = hookRunnerGenerator(onResponseHookIterator)
|
|
220
|
-
const
|
|
221
|
-
const
|
|
220
|
+
const preValidationHookRunner = hookRunnerGenerator(hookIterator)
|
|
221
|
+
const preHandlerHookRunner = hookRunnerGenerator(hookIterator)
|
|
222
222
|
const onTimeoutHookRunner = hookRunnerGenerator(hookIterator)
|
|
223
223
|
const onRequestHookRunner = hookRunnerGenerator(hookIterator)
|
|
224
224
|
|
|
@@ -267,6 +267,8 @@ function onSendHookRunner (functions, request, reply, payload, cb) {
|
|
|
267
267
|
next()
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
const preSerializationHookRunner = onSendHookRunner
|
|
271
|
+
|
|
270
272
|
function preParsingHookRunner (functions, request, reply, cb) {
|
|
271
273
|
let i = 0
|
|
272
274
|
|
|
@@ -360,11 +362,12 @@ module.exports = {
|
|
|
360
362
|
preParsingHookRunner,
|
|
361
363
|
onResponseHookRunner,
|
|
362
364
|
onSendHookRunner,
|
|
365
|
+
preSerializationHookRunner,
|
|
363
366
|
onRequestAbortHookRunner,
|
|
364
367
|
hookIterator,
|
|
365
368
|
hookRunnerApplication,
|
|
366
|
-
|
|
367
|
-
|
|
369
|
+
preHandlerHookRunner,
|
|
370
|
+
preValidationHookRunner,
|
|
368
371
|
onRequestHookRunner,
|
|
369
372
|
onTimeoutHookRunner,
|
|
370
373
|
lifecycleHooks,
|
package/lib/logger.js
CHANGED
|
@@ -144,7 +144,7 @@ function createChildLogger (context, logger, req, reqId, loggerOpts) {
|
|
|
144
144
|
}
|
|
145
145
|
const child = context.childLoggerFactory.call(context.server, logger, loggerBindings, loggerOpts || {}, req)
|
|
146
146
|
|
|
147
|
-
//
|
|
147
|
+
// Optimization: bypass validation if the factory is our own default factory
|
|
148
148
|
if (context.childLoggerFactory !== defaultChildLoggerFactory) {
|
|
149
149
|
validateLogger(child, true) // throw if the child is not a valid logger
|
|
150
150
|
}
|
package/lib/reply.js
CHANGED
|
@@ -23,7 +23,12 @@ const {
|
|
|
23
23
|
kOptions,
|
|
24
24
|
kRouteContext
|
|
25
25
|
} = require('./symbols.js')
|
|
26
|
-
const {
|
|
26
|
+
const {
|
|
27
|
+
onSendHookRunner,
|
|
28
|
+
onResponseHookRunner,
|
|
29
|
+
preHandlerHookRunner,
|
|
30
|
+
preSerializationHookRunner
|
|
31
|
+
} = require('./hooks')
|
|
27
32
|
|
|
28
33
|
const internals = require('./handleRequest')[Symbol.for('internals')]
|
|
29
34
|
const loggerUtils = require('./logger')
|
|
@@ -166,7 +171,7 @@ Reply.prototype.send = function (payload) {
|
|
|
166
171
|
|
|
167
172
|
if (this[kReplySerializer] !== null) {
|
|
168
173
|
if (typeof payload !== 'string') {
|
|
169
|
-
|
|
174
|
+
preSerializationHook(this, payload)
|
|
170
175
|
return this
|
|
171
176
|
} else {
|
|
172
177
|
payload = this[kReplySerializer](payload)
|
|
@@ -189,7 +194,7 @@ Reply.prototype.send = function (payload) {
|
|
|
189
194
|
}
|
|
190
195
|
}
|
|
191
196
|
if (typeof payload !== 'string') {
|
|
192
|
-
|
|
197
|
+
preSerializationHook(this, payload)
|
|
193
198
|
return this
|
|
194
199
|
}
|
|
195
200
|
}
|
|
@@ -233,7 +238,7 @@ Reply.prototype.header = function (key, value = '') {
|
|
|
233
238
|
key = key.toLowerCase()
|
|
234
239
|
|
|
235
240
|
if (this[kReplyHeaders][key] && key === 'set-cookie') {
|
|
236
|
-
// https://
|
|
241
|
+
// https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.2
|
|
237
242
|
if (typeof this[kReplyHeaders][key] === 'string') {
|
|
238
243
|
this[kReplyHeaders][key] = [this[kReplyHeaders][key]]
|
|
239
244
|
}
|
|
@@ -262,7 +267,7 @@ Reply.prototype.headers = function (headers) {
|
|
|
262
267
|
}
|
|
263
268
|
|
|
264
269
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer#directives
|
|
265
|
-
// https://
|
|
270
|
+
// https://datatracker.ietf.org/doc/html/rfc7230.html#chunked.trailer.part
|
|
266
271
|
const INVALID_TRAILERS = new Set([
|
|
267
272
|
'transfer-encoding',
|
|
268
273
|
'content-length',
|
|
@@ -476,21 +481,21 @@ Reply.prototype.then = function (fulfilled, rejected) {
|
|
|
476
481
|
})
|
|
477
482
|
}
|
|
478
483
|
|
|
479
|
-
function
|
|
484
|
+
function preSerializationHook (reply, payload) {
|
|
480
485
|
if (reply[kRouteContext].preSerialization !== null) {
|
|
481
|
-
|
|
486
|
+
preSerializationHookRunner(
|
|
482
487
|
reply[kRouteContext].preSerialization,
|
|
483
488
|
reply.request,
|
|
484
489
|
reply,
|
|
485
490
|
payload,
|
|
486
|
-
|
|
491
|
+
preSerializationHookEnd
|
|
487
492
|
)
|
|
488
493
|
} else {
|
|
489
|
-
|
|
494
|
+
preSerializationHookEnd(null, reply.request, reply, payload)
|
|
490
495
|
}
|
|
491
496
|
}
|
|
492
497
|
|
|
493
|
-
function
|
|
498
|
+
function preSerializationHookEnd (err, request, reply, payload) {
|
|
494
499
|
if (err != null) {
|
|
495
500
|
onErrorHook(reply, err)
|
|
496
501
|
return
|
|
@@ -505,7 +510,7 @@ function preserializeHookEnd (err, request, reply, payload) {
|
|
|
505
510
|
payload = serialize(reply[kRouteContext], payload, reply.raw.statusCode, reply[kReplyHeaders]['content-type'])
|
|
506
511
|
}
|
|
507
512
|
} catch (e) {
|
|
508
|
-
|
|
513
|
+
wrapSerializationError(e, reply)
|
|
509
514
|
onErrorHook(reply, e)
|
|
510
515
|
return
|
|
511
516
|
}
|
|
@@ -513,7 +518,7 @@ function preserializeHookEnd (err, request, reply, payload) {
|
|
|
513
518
|
onSendHook(reply, payload)
|
|
514
519
|
}
|
|
515
520
|
|
|
516
|
-
function
|
|
521
|
+
function wrapSerializationError (error, reply) {
|
|
517
522
|
error.serialization = reply[kRouteContext].config
|
|
518
523
|
}
|
|
519
524
|
|
|
@@ -571,7 +576,7 @@ function onSendEnd (reply, payload) {
|
|
|
571
576
|
}
|
|
572
577
|
|
|
573
578
|
if (payload === undefined || payload === null) {
|
|
574
|
-
// according to https://
|
|
579
|
+
// according to https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
|
|
575
580
|
// we cannot send a content-length for 304 and 204, and all status code
|
|
576
581
|
// < 200
|
|
577
582
|
// A sender MUST NOT send a Content-Length header field in any message
|
|
@@ -846,7 +851,7 @@ function notFound (reply) {
|
|
|
846
851
|
|
|
847
852
|
// preHandler hook
|
|
848
853
|
if (reply[kRouteContext].preHandler !== null) {
|
|
849
|
-
|
|
854
|
+
preHandlerHookRunner(
|
|
850
855
|
reply[kRouteContext].preHandler,
|
|
851
856
|
reply.request,
|
|
852
857
|
reply,
|
package/lib/request.js
CHANGED
|
@@ -51,8 +51,8 @@ function getTrustProxyFn (tp) {
|
|
|
51
51
|
}
|
|
52
52
|
if (typeof tp === 'string') {
|
|
53
53
|
// Support comma-separated tps
|
|
54
|
-
const
|
|
55
|
-
return proxyAddr.compile(
|
|
54
|
+
const values = tp.split(',').map(it => it.trim())
|
|
55
|
+
return proxyAddr.compile(values)
|
|
56
56
|
}
|
|
57
57
|
return proxyAddr.compile(tp)
|
|
58
58
|
}
|
package/lib/schemas.js
CHANGED
|
@@ -23,7 +23,7 @@ Schemas.prototype.add = function (inputSchema) {
|
|
|
23
23
|
: inputSchema
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
-
//
|
|
26
|
+
// developers can add schemas without $id, but with $def instead
|
|
27
27
|
const id = schema.$id
|
|
28
28
|
if (!id) {
|
|
29
29
|
throw new FST_ERR_SCH_MISSING_ID()
|
package/lib/server.js
CHANGED
|
@@ -132,7 +132,7 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
|
|
132
132
|
const isMainServerListening = mainServer.listening && serverOpts.serverFactory
|
|
133
133
|
|
|
134
134
|
let binding = 0
|
|
135
|
-
let
|
|
135
|
+
let bound = 0
|
|
136
136
|
if (!isMainServerListening) {
|
|
137
137
|
const primaryAddress = mainServer.address()
|
|
138
138
|
for (const adr of addresses) {
|
|
@@ -142,7 +142,7 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
|
|
142
142
|
host: adr.address,
|
|
143
143
|
port: primaryAddress.port,
|
|
144
144
|
cb: (_ignoreErr) => {
|
|
145
|
-
|
|
145
|
+
bound++
|
|
146
146
|
|
|
147
147
|
/* istanbul ignore next: the else won't be taken unless listening fails */
|
|
148
148
|
if (!_ignoreErr) {
|
|
@@ -172,7 +172,7 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
|
|
172
172
|
})
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
if (
|
|
175
|
+
if (bound === binding) {
|
|
176
176
|
// regardless of the error, we are done
|
|
177
177
|
onListen()
|
|
178
178
|
}
|
|
@@ -200,7 +200,7 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
|
|
200
200
|
// to the secondary servers. It is valid only when the user is
|
|
201
201
|
// listening on localhost
|
|
202
202
|
const originUnref = mainServer.unref
|
|
203
|
-
/*
|
|
203
|
+
/* c8 ignore next 4 */
|
|
204
204
|
mainServer.unref = function () {
|
|
205
205
|
originUnref.call(mainServer)
|
|
206
206
|
mainServer.emit('unref')
|
package/lib/validation.js
CHANGED
|
@@ -69,7 +69,7 @@ function compileSchemasForValidation (context, compile, isCustom) {
|
|
|
69
69
|
context[headersSchema] = compile({ schema: headers, method, url, httpPart: 'headers' })
|
|
70
70
|
} else if (headers) {
|
|
71
71
|
// The header keys are case insensitive
|
|
72
|
-
// https://
|
|
72
|
+
// https://datatracker.ietf.org/doc/html/rfc2616#section-4.2
|
|
73
73
|
const headersSchemaLowerCase = {}
|
|
74
74
|
Object.keys(headers).forEach(k => { headersSchemaLowerCase[k] = headers[k] })
|
|
75
75
|
if (headersSchemaLowerCase.required instanceof Array) {
|
package/lib/wrapThenable.js
CHANGED
|
@@ -18,10 +18,7 @@ function wrapThenable (thenable, reply) {
|
|
|
18
18
|
// the request may be terminated during the reply. in this situation,
|
|
19
19
|
// it require an extra checking of request.aborted to see whether
|
|
20
20
|
// the request is killed by client.
|
|
21
|
-
|
|
22
|
-
// however there is a race condition where the request is not
|
|
23
|
-
// aborted but only destroyed.
|
|
24
|
-
if (payload !== undefined || (reply.sent === false && reply.raw.headersSent === false && reply.request.raw.aborted === false && reply.request.raw.destroyed === false)) {
|
|
21
|
+
if (payload !== undefined || (reply.sent === false && reply.raw.headersSent === false && reply.request.raw.aborted === false)) {
|
|
25
22
|
// we use a try-catch internally to avoid adding a catch to another
|
|
26
23
|
// promise, increase promise perf by 10%
|
|
27
24
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "4.22.
|
|
3
|
+
"version": "4.22.2",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
"joi": "^17.9.2",
|
|
163
163
|
"json-schema-to-ts": "^2.9.1",
|
|
164
164
|
"JSONStream": "^1.3.5",
|
|
165
|
-
"markdownlint-cli2": "^0.
|
|
165
|
+
"markdownlint-cli2": "^0.9.2",
|
|
166
166
|
"proxyquire": "^2.1.3",
|
|
167
167
|
"self-cert": "^2.0.0",
|
|
168
168
|
"send": "^0.18.0",
|
|
@@ -23,9 +23,9 @@ test('check generated code syntax', async (t) => {
|
|
|
23
23
|
t.equal(result[0].fatalErrorCount, 0)
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
const
|
|
26
|
+
const isPrepublish = !!process.env.PREPUBLISH
|
|
27
27
|
|
|
28
|
-
test('ensure the current error serializer is latest', { skip: !
|
|
28
|
+
test('ensure the current error serializer is latest', { skip: !isPrepublish }, async (t) => {
|
|
29
29
|
t.plan(1)
|
|
30
30
|
|
|
31
31
|
const current = await fs.promises.readFile(path.resolve('lib/error-serializer.js'))
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const fastify = require('../')
|
|
5
|
+
const { request, setGlobalDispatcher, Agent } = require('undici')
|
|
6
|
+
|
|
7
|
+
setGlobalDispatcher(new Agent({
|
|
8
|
+
keepAliveTimeout: 10,
|
|
9
|
+
keepAliveMaxTimeout: 10
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
test('post empty body', async t => {
|
|
13
|
+
const app = fastify()
|
|
14
|
+
t.teardown(app.close.bind(app))
|
|
15
|
+
|
|
16
|
+
app.post('/bug', async (request, reply) => {
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
await app.listen({ port: 0 })
|
|
20
|
+
|
|
21
|
+
const res = await request(`http://127.0.0.1:${app.server.address().port}/bug`, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: {
|
|
24
|
+
'Content-Type': 'application/json'
|
|
25
|
+
},
|
|
26
|
+
body: JSON.stringify({ foo: 'bar' })
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
t.equal(res.statusCode, 200)
|
|
30
|
+
t.equal(await res.body.text(), '')
|
|
31
|
+
})
|
|
@@ -27,25 +27,3 @@ test('should reject immediately when reply[kReplyHijacked] is true', t => {
|
|
|
27
27
|
const thenable = Promise.reject(new Error('Reply sent already'))
|
|
28
28
|
wrapThenable(thenable, reply)
|
|
29
29
|
})
|
|
30
|
-
|
|
31
|
-
test('should not send the payload if the raw socket was destroyed but not aborted', async t => {
|
|
32
|
-
const reply = {
|
|
33
|
-
sent: false,
|
|
34
|
-
raw: {
|
|
35
|
-
headersSent: false
|
|
36
|
-
},
|
|
37
|
-
request: {
|
|
38
|
-
raw: {
|
|
39
|
-
aborted: false,
|
|
40
|
-
destroyed: true
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
send () {
|
|
44
|
-
t.fail('should not send')
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
const thenable = Promise.resolve()
|
|
48
|
-
wrapThenable(thenable, reply)
|
|
49
|
-
|
|
50
|
-
await thenable
|
|
51
|
-
})
|