fastify 3.5.0 → 3.8.0
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/ContentTypeParser.md +3 -0
- package/docs/Ecosystem.md +7 -2
- package/docs/Hooks.md +0 -5
- package/docs/Lifecycle.md +2 -2
- package/docs/Logging.md +1 -1
- package/docs/Recommendations.md +17 -0
- package/docs/Reply.md +2 -2
- package/docs/Request.md +4 -2
- package/docs/Routes.md +21 -3
- package/docs/Server.md +51 -3
- package/docs/Style-Guide.md +180 -0
- package/docs/TypeScript.md +359 -359
- package/docs/Validation-and-Serialization.md +11 -5
- package/examples/parser.js +1 -1
- package/fastify.d.ts +2 -2
- package/fastify.js +39 -7
- package/lib/contentTypeParser.js +16 -11
- package/lib/context.js +5 -19
- package/lib/decorate.js +1 -1
- package/lib/errors.js +2 -2
- package/lib/fourOhFour.js +8 -7
- package/lib/handleRequest.js +5 -5
- package/lib/hooks.js +4 -4
- package/lib/logger.js +7 -7
- package/lib/pluginUtils.js +4 -2
- package/lib/reply.js +27 -24
- package/lib/reqIdGenFactory.js +2 -2
- package/lib/request.js +20 -8
- package/lib/route.js +12 -10
- package/lib/schemas.js +1 -1
- package/lib/server.js +5 -5
- package/lib/symbols.js +2 -1
- package/lib/validation.js +9 -8
- package/lib/warnings.js +3 -0
- package/lib/wrapThenable.js +2 -2
- package/package.json +10 -10
- package/test/404s.test.js +15 -15
- package/test/async-await.test.js +7 -7
- package/test/custom-parser-async.test.js +2 -2
- package/test/custom-parser.test.js +38 -8
- package/test/emit-warning.test.js +31 -0
- package/test/fastify-instance.test.js +33 -1
- package/test/helper.js +1 -1
- package/test/hooks.test.js +6 -6
- package/test/http2/head.test.js +1 -1
- package/test/http2/plain.test.js +1 -1
- package/test/http2/secure-with-fallback.test.js +1 -1
- package/test/http2/secure.test.js +1 -1
- package/test/http2/unknown-http-method.test.js +1 -1
- package/test/https/https.test.js +2 -1
- package/test/inject.test.js +2 -2
- package/test/internals/all.test.js +1 -1
- package/test/internals/hookRunner.test.js +1 -1
- package/test/internals/logger.test.js +1 -1
- package/test/internals/reply.test.js +62 -7
- package/test/internals/request.test.js +31 -5
- package/test/internals/version.test.js +43 -0
- package/test/listen.test.js +12 -0
- package/test/logger.test.js +11 -11
- package/test/nullable-validation.test.js +108 -0
- package/test/pretty-print.test.js +9 -14
- package/test/reply-error.test.js +2 -2
- package/test/request-error.test.js +81 -0
- package/test/route-hooks.test.js +10 -10
- package/test/stream.test.js +11 -11
- package/test/types/fastify.test-d.ts +1 -2
- package/test/types/instance.test-d.ts +17 -3
- package/test/types/logger.test-d.ts +35 -2
- package/test/types/register.test-d.ts +16 -0
- package/test/types/request.test-d.ts +1 -1
- package/test/types/route.test-d.ts +5 -0
- package/test/validation-error-handling.test.js +66 -0
- package/test/versioned-routes.test.js +55 -0
- package/types/.eslintrc.json +4 -1
- package/types/content-type-parser.d.ts +0 -15
- package/types/hooks.d.ts +138 -16
- package/types/instance.d.ts +86 -14
- package/types/logger.d.ts +13 -11
- package/types/plugin.d.ts +5 -7
- package/types/register.d.ts +8 -7
- package/types/request.d.ts +3 -1
- package/types/route.d.ts +38 -58
- package/types/schema.d.ts +4 -4
- package/types/serverFactory.d.ts +9 -9
|
@@ -163,13 +163,19 @@ const bodyJsonSchema = {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
const queryStringJsonSchema = {
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
type: 'object',
|
|
167
|
+
properties: {
|
|
168
|
+
name: { type: 'string' },
|
|
169
|
+
excitement: { type: 'integer' }
|
|
170
|
+
}
|
|
168
171
|
}
|
|
169
172
|
|
|
170
173
|
const paramsJsonSchema = {
|
|
171
|
-
|
|
172
|
-
|
|
174
|
+
type: 'object',
|
|
175
|
+
properties: {
|
|
176
|
+
par1: { type: 'string' },
|
|
177
|
+
par2: { type: 'number' }
|
|
178
|
+
}
|
|
173
179
|
}
|
|
174
180
|
|
|
175
181
|
const headersJsonSchema = {
|
|
@@ -198,7 +204,7 @@ fastify.post('/the/url', { schema }, handler)
|
|
|
198
204
|
|
|
199
205
|
You can provide a list of plugins you want to use with Ajv:
|
|
200
206
|
|
|
201
|
-
> Refer to [`ajv options`](Server.md#
|
|
207
|
+
> Refer to [`ajv options`](Server.md#ajv) to check plugins format
|
|
202
208
|
|
|
203
209
|
```js
|
|
204
210
|
const fastify = require('fastify')({
|
package/examples/parser.js
CHANGED
|
@@ -16,7 +16,7 @@ fastify.addContentTypeParser('application/jsoff', function (request, payload, do
|
|
|
16
16
|
|
|
17
17
|
// curl -X POST -d 'hello=world' -H'Content-type: application/x-www-form-urlencoded' http://localhost:3000/
|
|
18
18
|
fastify.addContentTypeParser('application/x-www-form-urlencoded', function (request, payload, done) {
|
|
19
|
-
|
|
19
|
+
let body = ''
|
|
20
20
|
payload.on('data', function (data) {
|
|
21
21
|
body += data
|
|
22
22
|
})
|
package/fastify.d.ts
CHANGED
|
@@ -119,8 +119,8 @@ export type FastifyServerOptions<
|
|
|
119
119
|
type TrustProxyFunction = (address: string, hop: number) => boolean
|
|
120
120
|
|
|
121
121
|
/* Export all additional types */
|
|
122
|
-
export
|
|
123
|
-
export
|
|
122
|
+
export { FastifyRequest, RequestGenericInterface } from './types/request'
|
|
123
|
+
export { FastifyReply } from './types/reply'
|
|
124
124
|
export { FastifyPluginCallback, FastifyPluginAsync, FastifyPluginOptions, FastifyPlugin } from './types/plugin'
|
|
125
125
|
export { FastifyInstance } from './types/instance'
|
|
126
126
|
export { FastifyLoggerOptions, FastifyLoggerInstance, FastifyLogFn, LogLevel } from './types/logger'
|
package/fastify.js
CHANGED
|
@@ -5,6 +5,7 @@ const http = require('http')
|
|
|
5
5
|
const querystring = require('querystring')
|
|
6
6
|
let lightMyRequest
|
|
7
7
|
let version
|
|
8
|
+
let versionLoaded = false
|
|
8
9
|
|
|
9
10
|
const {
|
|
10
11
|
kAvvioBoot,
|
|
@@ -25,7 +26,8 @@ const {
|
|
|
25
26
|
kState,
|
|
26
27
|
kOptions,
|
|
27
28
|
kPluginNameChain,
|
|
28
|
-
kSchemaErrorFormatter
|
|
29
|
+
kSchemaErrorFormatter,
|
|
30
|
+
kErrorHandler
|
|
29
31
|
} = require('./lib/symbols.js')
|
|
30
32
|
|
|
31
33
|
const { createServer } = require('./lib/server')
|
|
@@ -57,6 +59,21 @@ const onBadUrlContext = {
|
|
|
57
59
|
onError: []
|
|
58
60
|
}
|
|
59
61
|
|
|
62
|
+
function defaultErrorHandler (error, request, reply) {
|
|
63
|
+
if (reply.statusCode < 500) {
|
|
64
|
+
reply.log.info(
|
|
65
|
+
{ res: reply, err: error },
|
|
66
|
+
error && error.message
|
|
67
|
+
)
|
|
68
|
+
} else {
|
|
69
|
+
reply.log.error(
|
|
70
|
+
{ req: request, res: reply, err: error },
|
|
71
|
+
error && error.message
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
reply.send(error)
|
|
75
|
+
}
|
|
76
|
+
|
|
60
77
|
function fastify (options) {
|
|
61
78
|
// Options validations
|
|
62
79
|
options = options || {}
|
|
@@ -160,6 +177,7 @@ function fastify (options) {
|
|
|
160
177
|
[kSchemas]: schemas,
|
|
161
178
|
[kValidatorCompiler]: null,
|
|
162
179
|
[kSchemaErrorFormatter]: options.schemaErrorFormatter,
|
|
180
|
+
[kErrorHandler]: defaultErrorHandler,
|
|
163
181
|
[kSerializerCompiler]: null,
|
|
164
182
|
[kReplySerializerDefault]: null,
|
|
165
183
|
[kContentTypeParser]: new ContentTypeParser(
|
|
@@ -219,6 +237,8 @@ function fastify (options) {
|
|
|
219
237
|
// custom parsers
|
|
220
238
|
addContentTypeParser: ContentTypeParser.helpers.addContentTypeParser,
|
|
221
239
|
hasContentTypeParser: ContentTypeParser.helpers.hasContentTypeParser,
|
|
240
|
+
getDefaultJsonParser: ContentTypeParser.defaultParsers.getDefaultJsonParser,
|
|
241
|
+
defaultTextParser: ContentTypeParser.defaultParsers.defaultTextParser,
|
|
222
242
|
// Fastify architecture methods (initialized by Avvio)
|
|
223
243
|
register: null,
|
|
224
244
|
after: null,
|
|
@@ -266,11 +286,16 @@ function fastify (options) {
|
|
|
266
286
|
},
|
|
267
287
|
version: {
|
|
268
288
|
get () {
|
|
269
|
-
if (
|
|
289
|
+
if (versionLoaded === false) {
|
|
270
290
|
version = loadVersion()
|
|
271
291
|
}
|
|
272
292
|
return version
|
|
273
293
|
}
|
|
294
|
+
},
|
|
295
|
+
errorHandler: {
|
|
296
|
+
get () {
|
|
297
|
+
return this[kErrorHandler]
|
|
298
|
+
}
|
|
274
299
|
}
|
|
275
300
|
})
|
|
276
301
|
|
|
@@ -504,8 +529,8 @@ function fastify (options) {
|
|
|
504
529
|
|
|
505
530
|
function onBadUrl (path, req, res) {
|
|
506
531
|
if (frameworkErrors) {
|
|
507
|
-
|
|
508
|
-
|
|
532
|
+
const id = genReqId(req)
|
|
533
|
+
const childLogger = logger.child({ reqId: id })
|
|
509
534
|
|
|
510
535
|
childLogger.info({ req }, 'incoming request')
|
|
511
536
|
|
|
@@ -558,7 +583,7 @@ function fastify (options) {
|
|
|
558
583
|
function setErrorHandler (func) {
|
|
559
584
|
throwIfAlreadyStarted('Cannot call "setErrorHandler" when fastify instance is already started!')
|
|
560
585
|
|
|
561
|
-
this
|
|
586
|
+
this[kErrorHandler] = func.bind(this)
|
|
562
587
|
return this
|
|
563
588
|
}
|
|
564
589
|
}
|
|
@@ -591,10 +616,17 @@ function wrapRouting (httpHandler, { rewriteUrl, logger }) {
|
|
|
591
616
|
}
|
|
592
617
|
|
|
593
618
|
function loadVersion () {
|
|
619
|
+
versionLoaded = true
|
|
594
620
|
const fs = require('fs')
|
|
595
621
|
const path = require('path')
|
|
596
|
-
|
|
597
|
-
|
|
622
|
+
try {
|
|
623
|
+
const pkgPath = path.join(__dirname, 'package.json')
|
|
624
|
+
fs.accessSync(pkgPath, fs.constants.R_OK)
|
|
625
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath))
|
|
626
|
+
return pkg.name === 'fastify' ? pkg.version : undefined
|
|
627
|
+
} catch (e) {
|
|
628
|
+
return undefined
|
|
629
|
+
}
|
|
598
630
|
}
|
|
599
631
|
|
|
600
632
|
/**
|
package/lib/contentTypeParser.js
CHANGED
|
@@ -81,9 +81,10 @@ ContentTypeParser.prototype.existingParser = function (contentType) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
ContentTypeParser.prototype.getParser = function (contentType) {
|
|
84
|
+
/* eslint-disable no-var */
|
|
84
85
|
for (var i = 0; i < this.parserList.length; i++) {
|
|
85
86
|
if (contentType.indexOf(this.parserList[i]) > -1) {
|
|
86
|
-
|
|
87
|
+
const parser = this.customParsers[this.parserList[i]]
|
|
87
88
|
this.cache.set(contentType, parser)
|
|
88
89
|
return parser
|
|
89
90
|
}
|
|
@@ -93,7 +94,7 @@ ContentTypeParser.prototype.getParser = function (contentType) {
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
ContentTypeParser.prototype.run = function (contentType, handler, request, reply) {
|
|
96
|
-
|
|
97
|
+
const parser = this.cache.get(contentType) || this.getParser(contentType)
|
|
97
98
|
|
|
98
99
|
if (parser === undefined) {
|
|
99
100
|
reply.send(new FST_ERR_CTP_INVALID_MEDIA_TYPE(contentType))
|
|
@@ -106,7 +107,7 @@ ContentTypeParser.prototype.run = function (contentType, handler, request, reply
|
|
|
106
107
|
done
|
|
107
108
|
)
|
|
108
109
|
} else {
|
|
109
|
-
|
|
110
|
+
let result
|
|
110
111
|
|
|
111
112
|
if (parser.isDeprecatedSignature) {
|
|
112
113
|
result = parser.fn(request[kRequestPayloadStream], done)
|
|
@@ -130,9 +131,9 @@ ContentTypeParser.prototype.run = function (contentType, handler, request, reply
|
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
function rawBody (request, reply, options, parser, done) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
const asString = parser.asString
|
|
135
|
+
const limit = options.limit === null ? parser.bodyLimit : options.limit
|
|
136
|
+
const contentLength = request.headers['content-length'] === undefined
|
|
136
137
|
? NaN
|
|
137
138
|
: Number.parseInt(request.headers['content-length'], 10)
|
|
138
139
|
|
|
@@ -141,8 +142,8 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
141
142
|
return
|
|
142
143
|
}
|
|
143
144
|
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
let receivedLength = 0
|
|
146
|
+
let body = asString === true ? '' : []
|
|
146
147
|
|
|
147
148
|
const payload = request[kRequestPayloadStream] || request.raw
|
|
148
149
|
|
|
@@ -197,7 +198,7 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
197
198
|
body = Buffer.concat(body)
|
|
198
199
|
}
|
|
199
200
|
|
|
200
|
-
|
|
201
|
+
const result = parser.fn(request, body, done)
|
|
201
202
|
if (result && typeof result.then === 'function') {
|
|
202
203
|
result.then(body => done(null, body), done)
|
|
203
204
|
}
|
|
@@ -211,9 +212,9 @@ function getDefaultJsonParser (onProtoPoisoning, onConstructorPoisoning) {
|
|
|
211
212
|
if (body === '' || body == null) {
|
|
212
213
|
return done(new FST_ERR_CTP_EMPTY_JSON_BODY(), undefined)
|
|
213
214
|
}
|
|
214
|
-
|
|
215
|
+
let json
|
|
215
216
|
try {
|
|
216
|
-
|
|
217
|
+
json = secureJson.parse(body, { protoAction: onProtoPoisoning, constructorAction: onConstructorPoisoning })
|
|
217
218
|
} catch (err) {
|
|
218
219
|
err.statusCode = 400
|
|
219
220
|
return done(err, undefined)
|
|
@@ -279,4 +280,8 @@ module.exports.helpers = {
|
|
|
279
280
|
addContentTypeParser,
|
|
280
281
|
hasContentTypeParser
|
|
281
282
|
}
|
|
283
|
+
module.exports.defaultParsers = {
|
|
284
|
+
getDefaultJsonParser,
|
|
285
|
+
defaultTextParser: defaultPlainTextParser
|
|
286
|
+
}
|
|
282
287
|
module.exports[kTestInternals] = { rawBody }
|
package/lib/context.js
CHANGED
|
@@ -17,7 +17,7 @@ function Context (schema, handler, Reply, Request, contentTypeParser, config, er
|
|
|
17
17
|
this.preHandler = null
|
|
18
18
|
this.onResponse = null
|
|
19
19
|
this.config = config
|
|
20
|
-
this.errorHandler = errorHandler
|
|
20
|
+
this.errorHandler = errorHandler
|
|
21
21
|
this._middie = null
|
|
22
22
|
this._parserOptions = { limit: bodyLimit || null }
|
|
23
23
|
this.logLevel = logLevel
|
|
@@ -28,26 +28,12 @@ function Context (schema, handler, Reply, Request, contentTypeParser, config, er
|
|
|
28
28
|
this.schemaErrorFormatter = schemaErrorFormatter || defaultSchemaErrorFormatter
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function defaultErrorHandler (error, request, reply) {
|
|
32
|
-
if (reply.statusCode >= 500) {
|
|
33
|
-
reply.log.error(
|
|
34
|
-
{ req: request, res: reply, err: error },
|
|
35
|
-
error && error.message
|
|
36
|
-
)
|
|
37
|
-
} else if (reply.statusCode >= 400) {
|
|
38
|
-
reply.log.info(
|
|
39
|
-
{ res: reply, err: error },
|
|
40
|
-
error && error.message
|
|
41
|
-
)
|
|
42
|
-
}
|
|
43
|
-
reply.send(error)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
31
|
function defaultSchemaErrorFormatter (errors, dataVar) {
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
let text = ''
|
|
33
|
+
const separator = ', '
|
|
34
|
+
/* eslint-disable no-var */
|
|
49
35
|
for (var i = 0; i < errors.length; i++) {
|
|
50
|
-
|
|
36
|
+
const e = errors[i]
|
|
51
37
|
text += dataVar + (e.dataPath || '') + ' ' + e.message + separator
|
|
52
38
|
}
|
|
53
39
|
return new Error(text.slice(0, -separator.length))
|
package/lib/decorate.js
CHANGED
|
@@ -56,7 +56,7 @@ function checkReplyExistence (name) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
function checkDependencies (instance, deps) {
|
|
59
|
-
for (
|
|
59
|
+
for (let i = 0; i < deps.length; i++) {
|
|
60
60
|
if (!checkExistence(instance, deps[i])) {
|
|
61
61
|
throw new FST_ERR_DEC_MISSING_DEPENDENCY(deps[i])
|
|
62
62
|
}
|
package/lib/errors.js
CHANGED
|
@@ -171,8 +171,8 @@ const codes = {
|
|
|
171
171
|
/**
|
|
172
172
|
* wrapThenable
|
|
173
173
|
*/
|
|
174
|
-
|
|
175
|
-
'
|
|
174
|
+
FST_ERR_PROMISE_NOT_FULFILLED: createError(
|
|
175
|
+
'FST_ERR_PROMISE_NOT_FULFILLED',
|
|
176
176
|
"Promise may not be fulfilled with 'undefined' when statusCode is not 204"
|
|
177
177
|
),
|
|
178
178
|
|
package/lib/fourOhFour.js
CHANGED
|
@@ -15,7 +15,8 @@ const {
|
|
|
15
15
|
kBodyLimit,
|
|
16
16
|
kLogLevel,
|
|
17
17
|
kFourOhFourContext,
|
|
18
|
-
kHooks
|
|
18
|
+
kHooks,
|
|
19
|
+
kErrorHandler
|
|
19
20
|
} = require('./symbols.js')
|
|
20
21
|
const { lifecycleHooks } = require('./hooks')
|
|
21
22
|
const fourOhFourContext = {
|
|
@@ -28,7 +29,7 @@ const fourOhFourContext = {
|
|
|
28
29
|
/**
|
|
29
30
|
* Each fastify instance have a:
|
|
30
31
|
* kFourOhFourLevelInstance: point to a fastify instance that has the 404 handler setted
|
|
31
|
-
* kCanSetNotFoundHandler: bool to track if the 404 handler has
|
|
32
|
+
* kCanSetNotFoundHandler: bool to track if the 404 handler has already been set
|
|
32
33
|
* kFourOhFour: the singleton instance of this 404 module
|
|
33
34
|
* kFourOhFourContext: the context in the reply object where the handler will be executed
|
|
34
35
|
*/
|
|
@@ -124,7 +125,7 @@ function fourOhFour (options) {
|
|
|
124
125
|
this[kRequest],
|
|
125
126
|
this[kContentTypeParser],
|
|
126
127
|
opts.config || {},
|
|
127
|
-
this
|
|
128
|
+
this[kErrorHandler],
|
|
128
129
|
this[kBodyLimit],
|
|
129
130
|
this[kLogLevel]
|
|
130
131
|
)
|
|
@@ -155,13 +156,13 @@ function fourOhFour (options) {
|
|
|
155
156
|
// we might want to do some hard debugging
|
|
156
157
|
// here, let's print out as much info as
|
|
157
158
|
// we can
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
const id = genReqId(req)
|
|
160
|
+
const childLogger = logger.child({ reqId: id })
|
|
160
161
|
|
|
161
162
|
childLogger.info({ req }, 'incoming request')
|
|
162
163
|
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
const request = new Request(id, null, req, null, childLogger, fourOhFourContext)
|
|
165
|
+
const reply = new Reply(res, request, childLogger)
|
|
165
166
|
|
|
166
167
|
request.log.warn('the default handler for 404 did not catch this, this is likely a fastify bug, please report it')
|
|
167
168
|
request.log.warn(router.prettyPrint())
|
package/lib/handleRequest.js
CHANGED
|
@@ -11,15 +11,15 @@ function handleRequest (err, request, reply) {
|
|
|
11
11
|
return
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const method = request.raw.method
|
|
15
|
+
const headers = request.headers
|
|
16
16
|
|
|
17
17
|
if (method === 'GET' || method === 'HEAD') {
|
|
18
18
|
handler(request, reply)
|
|
19
19
|
return
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
const contentType = headers['content-type']
|
|
23
23
|
|
|
24
24
|
if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
|
|
25
25
|
if (contentType === undefined) {
|
|
@@ -84,7 +84,7 @@ function preValidationCallback (err, request, reply) {
|
|
|
84
84
|
return
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
const result = validateSchema(reply.context, request)
|
|
88
88
|
if (result) {
|
|
89
89
|
if (reply.context.attachValidation === false) {
|
|
90
90
|
reply.code(400).send(result)
|
|
@@ -118,7 +118,7 @@ function preHandlerCallback (err, request, reply) {
|
|
|
118
118
|
return
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
let result
|
|
122
122
|
|
|
123
123
|
try {
|
|
124
124
|
result = reply.context.handler(request, reply)
|
package/lib/hooks.js
CHANGED
|
@@ -77,8 +77,8 @@ function buildHooks (h) {
|
|
|
77
77
|
|
|
78
78
|
function hookRunnerApplication (hookName, boot, server, cb) {
|
|
79
79
|
const hooks = server[kHooks][hookName]
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
let i = 0
|
|
81
|
+
let c = 0
|
|
82
82
|
|
|
83
83
|
next()
|
|
84
84
|
|
|
@@ -151,7 +151,7 @@ function hookRunnerApplication (hookName, boot, server, cb) {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
function hookRunner (functions, runner, request, reply, cb) {
|
|
154
|
-
|
|
154
|
+
let i = 0
|
|
155
155
|
|
|
156
156
|
function next (err) {
|
|
157
157
|
if (err || i === functions.length) {
|
|
@@ -182,7 +182,7 @@ function hookRunner (functions, runner, request, reply, cb) {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
function onSendHookRunner (functions, request, reply, payload, cb) {
|
|
185
|
-
|
|
185
|
+
let i = 0
|
|
186
186
|
|
|
187
187
|
function next (err, newPayload) {
|
|
188
188
|
if (err) {
|
package/lib/logger.js
CHANGED
|
@@ -23,9 +23,9 @@ function createPinoLogger (opts, stream) {
|
|
|
23
23
|
delete opts.file
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
const prevLogger = opts.logger
|
|
27
|
+
const prevGenReqId = opts.genReqId
|
|
28
|
+
let logger = null
|
|
29
29
|
|
|
30
30
|
if (prevLogger) {
|
|
31
31
|
opts.logger = undefined
|
|
@@ -53,7 +53,7 @@ const serializers = {
|
|
|
53
53
|
version: req.headers['accept-version'],
|
|
54
54
|
hostname: req.hostname,
|
|
55
55
|
remoteAddress: req.ip,
|
|
56
|
-
remotePort: req.
|
|
56
|
+
remotePort: req.socket.remotePort
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
err: pino.stdSerializers.err,
|
|
@@ -65,7 +65,7 @@ const serializers = {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
function now () {
|
|
68
|
-
|
|
68
|
+
const ts = process.hrtime()
|
|
69
69
|
return (ts[0] * 1e3) + (ts[1] / 1e6)
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -105,9 +105,9 @@ function isValidLogger (logger) {
|
|
|
105
105
|
return false
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
let result = true
|
|
109
109
|
const methods = ['info', 'error', 'debug', 'fatal', 'warn', 'trace', 'child']
|
|
110
|
-
for (
|
|
110
|
+
for (let i = 0; i < methods.length; i += 1) {
|
|
111
111
|
if (!logger[methods[i]] || typeof logger[methods[i]] !== 'function') {
|
|
112
112
|
result = false
|
|
113
113
|
break
|
package/lib/pluginUtils.js
CHANGED
|
@@ -20,7 +20,7 @@ function getPluginName (func) {
|
|
|
20
20
|
const cache = require.cache
|
|
21
21
|
const keys = Object.keys(cache)
|
|
22
22
|
|
|
23
|
-
for (
|
|
23
|
+
for (let i = 0; i < keys.length; i++) {
|
|
24
24
|
if (cache[keys[i]].exports === func) {
|
|
25
25
|
return keys[i]
|
|
26
26
|
}
|
|
@@ -107,7 +107,9 @@ function registerPluginName (fn) {
|
|
|
107
107
|
|
|
108
108
|
function registerPlugin (fn) {
|
|
109
109
|
registerPluginName.call(this, fn)
|
|
110
|
-
|
|
110
|
+
if (this.version !== undefined) {
|
|
111
|
+
checkVersion.call(this, fn)
|
|
112
|
+
}
|
|
111
113
|
checkDecorators.call(this, fn)
|
|
112
114
|
checkDependencies.call(this, fn)
|
|
113
115
|
return shouldSkipOverride(fn)
|
package/lib/reply.js
CHANGED
|
@@ -125,8 +125,8 @@ Reply.prototype.send = function (payload) {
|
|
|
125
125
|
return this
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
const contentType = this.getHeader('content-type')
|
|
129
|
+
const hasContentType = contentType !== undefined
|
|
130
130
|
|
|
131
131
|
if (payload !== null) {
|
|
132
132
|
if (Buffer.isBuffer(payload) || typeof payload.pipe === 'function') {
|
|
@@ -184,8 +184,8 @@ Reply.prototype.send = function (payload) {
|
|
|
184
184
|
|
|
185
185
|
Reply.prototype.getHeader = function (key) {
|
|
186
186
|
key = key.toLowerCase()
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
const res = this.raw
|
|
188
|
+
let value = this[kReplyHeaders][key]
|
|
189
189
|
if (value === undefined && res.hasHeader(key)) {
|
|
190
190
|
value = res.getHeader(key)
|
|
191
191
|
}
|
|
@@ -211,7 +211,7 @@ Reply.prototype.removeHeader = function (key) {
|
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
Reply.prototype.header = function (key, value) {
|
|
214
|
-
|
|
214
|
+
const _key = key.toLowerCase()
|
|
215
215
|
|
|
216
216
|
// default the value to ''
|
|
217
217
|
value = value === undefined ? '' : value
|
|
@@ -233,7 +233,8 @@ Reply.prototype.header = function (key, value) {
|
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
Reply.prototype.headers = function (headers) {
|
|
236
|
-
|
|
236
|
+
const keys = Object.keys(headers)
|
|
237
|
+
/* eslint-disable no-var */
|
|
237
238
|
for (var i = 0; i < keys.length; i++) {
|
|
238
239
|
this.header(keys[i], headers[keys[i]])
|
|
239
240
|
}
|
|
@@ -289,7 +290,7 @@ Reply.prototype.callNotFound = function () {
|
|
|
289
290
|
}
|
|
290
291
|
|
|
291
292
|
Reply.prototype.getResponseTime = function () {
|
|
292
|
-
|
|
293
|
+
let responseTime = 0
|
|
293
294
|
|
|
294
295
|
if (this[kReplyStartTime] !== undefined) {
|
|
295
296
|
responseTime = now() - this[kReplyStartTime]
|
|
@@ -303,9 +304,9 @@ Reply.prototype.getResponseTime = function () {
|
|
|
303
304
|
// - https://github.com/fastify/fastify/issues/1864 for the discussions
|
|
304
305
|
// - https://promisesaplus.com/ for the definition of thenable
|
|
305
306
|
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then for the signature
|
|
306
|
-
Reply.prototype.then = function (
|
|
307
|
+
Reply.prototype.then = function (fulfilled, rejected) {
|
|
307
308
|
if (this.sent) {
|
|
308
|
-
|
|
309
|
+
fulfilled()
|
|
309
310
|
return
|
|
310
311
|
}
|
|
311
312
|
|
|
@@ -317,7 +318,7 @@ Reply.prototype.then = function (fullfilled, rejected) {
|
|
|
317
318
|
rejected(err)
|
|
318
319
|
}
|
|
319
320
|
} else {
|
|
320
|
-
|
|
321
|
+
fulfilled()
|
|
321
322
|
}
|
|
322
323
|
})
|
|
323
324
|
}
|
|
@@ -377,8 +378,9 @@ function wrapOnSendEnd (err, request, reply, payload) {
|
|
|
377
378
|
}
|
|
378
379
|
|
|
379
380
|
function onSendEnd (reply, payload) {
|
|
380
|
-
|
|
381
|
-
|
|
381
|
+
const res = reply.raw
|
|
382
|
+
const req = reply.request
|
|
383
|
+
const statusCode = res.statusCode
|
|
382
384
|
|
|
383
385
|
if (payload === undefined || payload === null) {
|
|
384
386
|
reply[kReplySent] = true
|
|
@@ -386,7 +388,8 @@ function onSendEnd (reply, payload) {
|
|
|
386
388
|
// according to https://tools.ietf.org/html/rfc7230#section-3.3.2
|
|
387
389
|
// we cannot send a content-length for 304 and 204, and all status code
|
|
388
390
|
// < 200.
|
|
389
|
-
|
|
391
|
+
// For HEAD we don't overwrite the `content-length`
|
|
392
|
+
if (statusCode >= 200 && statusCode !== 204 && statusCode !== 304 && req.method !== 'HEAD') {
|
|
390
393
|
reply[kReplyHeaders]['content-length'] = '0'
|
|
391
394
|
}
|
|
392
395
|
|
|
@@ -428,8 +431,8 @@ function logStreamError (logger, err, res) {
|
|
|
428
431
|
}
|
|
429
432
|
|
|
430
433
|
function sendStream (payload, res, reply) {
|
|
431
|
-
|
|
432
|
-
|
|
434
|
+
let sourceOpen = true
|
|
435
|
+
let errorLogged = false
|
|
433
436
|
|
|
434
437
|
eos(payload, { readable: true, writable: false }, function (err) {
|
|
435
438
|
sourceOpen = false
|
|
@@ -472,7 +475,7 @@ function sendStream (payload, res, reply) {
|
|
|
472
475
|
// writeHead, and we need to resort to setHeader, which will trigger
|
|
473
476
|
// a writeHead when there is data to send.
|
|
474
477
|
if (!res.headersSent) {
|
|
475
|
-
for (
|
|
478
|
+
for (const key in reply[kReplyHeaders]) {
|
|
476
479
|
res.setHeader(key, reply[kReplyHeaders][key])
|
|
477
480
|
}
|
|
478
481
|
} else {
|
|
@@ -499,8 +502,8 @@ function onErrorHook (reply, error, cb) {
|
|
|
499
502
|
|
|
500
503
|
function handleError (reply, error, cb) {
|
|
501
504
|
reply[kReplyIsRunningOnErrorHook] = false
|
|
502
|
-
|
|
503
|
-
|
|
505
|
+
const res = reply.raw
|
|
506
|
+
let statusCode = res.statusCode
|
|
504
507
|
statusCode = (statusCode >= 400) ? statusCode : 500
|
|
505
508
|
// treat undefined and null as same
|
|
506
509
|
if (error != null) {
|
|
@@ -516,20 +519,20 @@ function handleError (reply, error, cb) {
|
|
|
516
519
|
|
|
517
520
|
res.statusCode = statusCode
|
|
518
521
|
|
|
519
|
-
|
|
522
|
+
const errorHandler = reply.context.errorHandler
|
|
520
523
|
if (errorHandler && reply[kReplyErrorHandlerCalled] === false) {
|
|
521
524
|
reply[kReplySent] = false
|
|
522
525
|
reply[kReplyIsError] = false
|
|
523
526
|
reply[kReplyErrorHandlerCalled] = true
|
|
524
527
|
reply[kReplyHeaders]['content-length'] = undefined
|
|
525
|
-
|
|
528
|
+
const result = errorHandler(error, reply.request, reply)
|
|
526
529
|
if (result && typeof result.then === 'function') {
|
|
527
530
|
wrapThenable(result, reply)
|
|
528
531
|
}
|
|
529
532
|
return
|
|
530
533
|
}
|
|
531
534
|
|
|
532
|
-
|
|
535
|
+
const payload = serializeError({
|
|
533
536
|
error: statusCodes[statusCode + ''],
|
|
534
537
|
code: error.code,
|
|
535
538
|
message: error.message || '',
|
|
@@ -552,11 +555,11 @@ function handleError (reply, error, cb) {
|
|
|
552
555
|
function setupResponseListeners (reply) {
|
|
553
556
|
reply[kReplyStartTime] = now()
|
|
554
557
|
|
|
555
|
-
|
|
558
|
+
const onResFinished = err => {
|
|
556
559
|
reply.raw.removeListener('finish', onResFinished)
|
|
557
560
|
reply.raw.removeListener('error', onResFinished)
|
|
558
561
|
|
|
559
|
-
|
|
562
|
+
const ctx = reply.context
|
|
560
563
|
|
|
561
564
|
if (ctx && ctx.onResponse !== null) {
|
|
562
565
|
hookRunner(
|
|
@@ -584,7 +587,7 @@ function onResponseCallback (err, request, reply) {
|
|
|
584
587
|
return
|
|
585
588
|
}
|
|
586
589
|
|
|
587
|
-
|
|
590
|
+
const responseTime = reply.getResponseTime()
|
|
588
591
|
|
|
589
592
|
if (err != null) {
|
|
590
593
|
reply.log.error({
|
package/lib/reqIdGenFactory.js
CHANGED