fastify 3.27.4 → 4.0.0-alpha.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.
- package/.taprc +3 -0
- package/README.md +7 -7
- package/build/build-error-serializer.js +27 -0
- package/build/build-validation.js +47 -35
- package/docs/Guides/Database.md +320 -0
- package/docs/Guides/Ecosystem.md +9 -0
- package/docs/Guides/Getting-Started.md +7 -7
- package/docs/Guides/Plugins-Guide.md +1 -1
- package/docs/Guides/Serverless.md +3 -3
- package/docs/Guides/Testing.md +2 -2
- package/docs/Migration-Guide-V4.md +12 -0
- package/docs/Reference/ContentTypeParser.md +4 -0
- package/docs/Reference/Decorators.md +2 -2
- package/docs/Reference/Encapsulation.md +2 -2
- package/docs/Reference/Errors.md +51 -6
- package/docs/Reference/HTTP2.md +3 -3
- package/docs/Reference/Hooks.md +4 -7
- package/docs/Reference/LTS.md +5 -4
- package/docs/Reference/Plugins.md +3 -3
- package/docs/Reference/Reply.md +73 -22
- package/docs/Reference/Request.md +1 -3
- package/docs/Reference/Routes.md +22 -15
- package/docs/Reference/Server.md +69 -119
- package/docs/Reference/TypeScript.md +20 -22
- package/docs/Reference/Validation-and-Serialization.md +30 -55
- package/docs/Type-Providers.md +257 -0
- package/examples/asyncawait.js +1 -1
- package/examples/benchmark/hooks-benchmark-async-await.js +1 -1
- package/examples/benchmark/hooks-benchmark.js +1 -1
- package/examples/benchmark/simple.js +1 -1
- package/examples/hooks.js +2 -2
- package/examples/http2.js +1 -1
- package/examples/https.js +1 -1
- package/examples/parser.js +13 -3
- package/examples/route-prefix.js +1 -1
- package/examples/shared-schema.js +1 -1
- package/examples/simple-stream.js +18 -0
- package/examples/simple.js +1 -1
- package/examples/simple.mjs +1 -1
- package/examples/typescript-server.ts +1 -1
- package/examples/use-plugin.js +1 -1
- package/fastify.d.ts +34 -22
- package/fastify.js +40 -36
- package/lib/configValidator.js +902 -1023
- package/lib/contentTypeParser.js +6 -16
- package/lib/context.js +36 -10
- package/lib/decorate.js +3 -1
- package/lib/error-handler.js +158 -0
- package/lib/error-serializer.js +257 -0
- package/lib/errors.js +51 -9
- package/lib/fourOhFour.js +31 -20
- package/lib/handleRequest.js +10 -13
- package/lib/hooks.js +14 -9
- package/lib/pluginOverride.js +0 -3
- package/lib/pluginUtils.js +3 -2
- package/lib/reply.js +121 -175
- package/lib/request.js +13 -10
- package/lib/route.js +131 -138
- package/lib/schema-controller.js +2 -2
- package/lib/schemas.js +27 -1
- package/lib/server.js +242 -116
- package/lib/symbols.js +5 -3
- package/lib/validation.js +11 -9
- package/lib/warnings.js +4 -12
- package/lib/wrapThenable.js +4 -11
- package/package.json +37 -39
- package/test/404s.test.js +258 -125
- package/test/500s.test.js +3 -3
- package/test/als.test.js +1 -1
- package/test/async-await.test.js +20 -76
- package/test/bodyLimit.test.js +1 -1
- package/test/build-certificate.js +6 -7
- package/test/case-insensitive.test.js +4 -4
- package/test/close-pipelining.test.js +2 -2
- package/test/close.test.js +11 -11
- package/test/content-parser.test.js +32 -0
- package/test/context-config.test.js +52 -0
- package/test/custom-http-server.test.js +14 -7
- package/test/custom-parser-async.test.js +1 -66
- package/test/custom-parser.test.js +92 -159
- package/test/custom-querystring-parser.test.js +3 -3
- package/test/decorator.test.js +11 -13
- package/test/delete.test.js +6 -6
- package/test/encapsulated-error-handler.test.js +50 -0
- package/test/esm/index.test.js +0 -14
- package/test/fastify-instance.test.js +4 -4
- package/test/fluent-schema.test.js +4 -4
- package/test/genReqId.test.js +1 -1
- package/test/get.test.js +4 -4
- package/test/handler-context.test.js +2 -2
- package/test/head.test.js +1 -1
- package/test/helper.js +19 -4
- package/test/hooks-async.test.js +15 -48
- package/test/hooks.on-ready.test.js +10 -5
- package/test/hooks.test.js +78 -119
- package/test/http2/closing.test.js +10 -16
- package/test/http2/constraint.test.js +1 -1
- 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 +4 -10
- package/test/https/custom-https-server.test.js +12 -6
- package/test/https/https.test.js +1 -1
- package/test/input-validation.js +3 -3
- package/test/internals/handleRequest.test.js +6 -43
- package/test/internals/initialConfig.test.js +41 -12
- package/test/internals/logger.test.js +2 -2
- package/test/internals/reply.test.js +317 -48
- package/test/internals/request.test.js +13 -7
- package/test/internals/server.test.js +88 -0
- package/test/listen.deprecated.test.js +202 -0
- package/test/listen.test.js +140 -145
- package/test/logger.test.js +82 -42
- package/test/maxRequestsPerSocket.test.js +8 -6
- package/test/middleware.test.js +2 -25
- package/test/nullable-validation.test.js +53 -16
- package/test/output-validation.test.js +1 -1
- package/test/plugin.test.js +47 -21
- package/test/pretty-print.test.js +22 -10
- package/test/promises.test.js +1 -1
- package/test/proto-poisoning.test.js +6 -6
- package/test/register.test.js +3 -3
- package/test/reply-error.test.js +126 -15
- package/test/reply-trailers.test.js +270 -0
- package/test/request-error.test.js +3 -6
- package/test/route-hooks.test.js +18 -18
- package/test/route-prefix.test.js +2 -1
- package/test/route.test.js +206 -22
- package/test/router-options.test.js +2 -2
- package/test/schema-examples.test.js +11 -5
- package/test/schema-feature.test.js +25 -20
- package/test/schema-serialization.test.js +9 -9
- package/test/schema-special-usage.test.js +5 -153
- package/test/schema-validation.test.js +9 -9
- package/test/skip-reply-send.test.js +2 -2
- package/test/stream.test.js +82 -23
- package/test/throw.test.js +8 -5
- package/test/trust-proxy.test.js +6 -6
- package/test/type-provider.test.js +20 -0
- package/test/types/fastify.test-d.ts +10 -18
- package/test/types/hooks.test-d.ts +61 -5
- package/test/types/import.js +2 -0
- package/test/types/import.ts +1 -0
- package/test/types/instance.test-d.ts +68 -17
- package/test/types/logger.test-d.ts +44 -15
- package/test/types/reply.test-d.ts +2 -1
- package/test/types/request.test-d.ts +71 -1
- package/test/types/route.test-d.ts +8 -2
- package/test/types/schema.test-d.ts +2 -39
- package/test/types/type-provider.test-d.ts +424 -0
- package/test/url-rewriting.test.js +3 -3
- package/test/validation-error-handling.test.js +8 -8
- package/test/versioned-routes.test.js +30 -18
- package/test/wrapThenable.test.js +7 -6
- package/types/content-type-parser.d.ts +17 -8
- package/types/hooks.d.ts +182 -85
- package/types/instance.d.ts +286 -118
- package/types/logger.d.ts +18 -104
- package/types/plugin.d.ts +10 -4
- package/types/reply.d.ts +18 -12
- package/types/request.d.ts +13 -8
- package/types/route.d.ts +62 -34
- package/types/schema.d.ts +1 -1
- package/types/type-provider.d.ts +99 -0
- package/types/utils.d.ts +1 -1
- package/lib/schema-compilers.js +0 -12
- package/test/emit-warning.test.js +0 -166
package/lib/server.js
CHANGED
|
@@ -1,16 +1,214 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const assert = require('assert')
|
|
4
3
|
const http = require('http')
|
|
5
4
|
const https = require('https')
|
|
5
|
+
const dns = require('dns')
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const warnings = require('./warnings')
|
|
8
|
+
const { kState, kOptions, kServerBindings } = require('./symbols')
|
|
8
9
|
const { FST_ERR_HTTP2_INVALID_VERSION, FST_ERR_REOPENED_CLOSE_SERVER, FST_ERR_REOPENED_SERVER } = require('./errors')
|
|
9
10
|
|
|
11
|
+
module.exports = createServer
|
|
12
|
+
|
|
10
13
|
function createServer (options, httpHandler) {
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
const server = getServerInstance(options, httpHandler)
|
|
15
|
+
|
|
16
|
+
return { server, listen }
|
|
17
|
+
|
|
18
|
+
// `this` is the Fastify object
|
|
19
|
+
function listen (listenOptions, ...args) {
|
|
20
|
+
let cb = args.slice(-1).pop()
|
|
21
|
+
// When the variadic signature deprecation is complete, the function
|
|
22
|
+
// declaration should become:
|
|
23
|
+
// function listen (listenOptions = { port: 0, host: 'localhost' }, cb = undefined)
|
|
24
|
+
// Upon doing so, the `normalizeListenArgs` function is no longer needed,
|
|
25
|
+
// and all of this preamble to feed it correctly also no longer needed.
|
|
26
|
+
const firstArgType = Object.prototype.toString.call(arguments[0])
|
|
27
|
+
if (arguments.length === 0) {
|
|
28
|
+
listenOptions = normalizeListenArgs([])
|
|
29
|
+
} else if (arguments.length > 0 && (firstArgType !== '[object Object]' && firstArgType !== '[object Function]')) {
|
|
30
|
+
warnings.emit('FSTDEP011')
|
|
31
|
+
listenOptions = normalizeListenArgs(Array.from(arguments))
|
|
32
|
+
cb = listenOptions.cb
|
|
33
|
+
} else if (args.length > 1) {
|
|
34
|
+
// `.listen(obj, a, ..., n, callback )`
|
|
35
|
+
warnings.emit('FSTDEP011')
|
|
36
|
+
// Deal with `.listen(port, host, backlog, [cb])`
|
|
37
|
+
const hostPath = listenOptions.path ? [listenOptions.path] : [listenOptions.port ?? 0, listenOptions.host ?? 'localhost']
|
|
38
|
+
Object.assign(listenOptions, normalizeListenArgs([...hostPath, ...args]))
|
|
39
|
+
} else {
|
|
40
|
+
listenOptions.cb = cb
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { host = 'localhost' } = listenOptions
|
|
44
|
+
if (Object.prototype.hasOwnProperty.call(listenOptions, 'host') === false) {
|
|
45
|
+
listenOptions.host = host
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (host === 'localhost') {
|
|
49
|
+
listenOptions.cb = (err, address) => {
|
|
50
|
+
if (err) {
|
|
51
|
+
// the server did not start
|
|
52
|
+
cb(err, address)
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
|
|
57
|
+
this[kState].listening = true
|
|
58
|
+
cb(null, address)
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// https://github.com/nodejs/node/issues/9390
|
|
64
|
+
// If listening to 'localhost', listen to both 127.0.0.1 or ::1 if they are available.
|
|
65
|
+
// If listening to 127.0.0.1, only listen to 127.0.0.1.
|
|
66
|
+
// If listening to ::1, only listen to ::1.
|
|
67
|
+
|
|
68
|
+
if (cb === undefined) {
|
|
69
|
+
const listening = listenPromise.call(this, server, listenOptions)
|
|
70
|
+
/* istanbul ignore else */
|
|
71
|
+
if (host === 'localhost') {
|
|
72
|
+
return listening.then(address => {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
|
|
75
|
+
this[kState].listening = true
|
|
76
|
+
resolve(address)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
return listening
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.ready(listenCallback.call(this, server, listenOptions))
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, onListen) {
|
|
89
|
+
// the main server is started, we need to start the secondary servers
|
|
90
|
+
this[kState].listening = false
|
|
91
|
+
|
|
92
|
+
// let's check if we need to bind additional addresses
|
|
93
|
+
dns.lookup(listenOptions.host, { all: true }, (dnsErr, addresses) => {
|
|
94
|
+
if (dnsErr) {
|
|
95
|
+
// not blocking the main server listening
|
|
96
|
+
// this.log.warn('dns.lookup error:', dnsErr)
|
|
97
|
+
onListen()
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let binding = 0
|
|
102
|
+
let binded = 0
|
|
103
|
+
const primaryAddress = mainServer.address()
|
|
104
|
+
for (const adr of addresses) {
|
|
105
|
+
if (adr.address !== primaryAddress.address) {
|
|
106
|
+
binding++
|
|
107
|
+
const secondaryOpts = Object.assign({}, listenOptions, {
|
|
108
|
+
host: adr.address,
|
|
109
|
+
port: primaryAddress.port,
|
|
110
|
+
cb: (_ignoreErr) => {
|
|
111
|
+
binded++
|
|
112
|
+
|
|
113
|
+
if (!_ignoreErr) {
|
|
114
|
+
this[kServerBindings].push(secondaryServer)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (binded === binding) {
|
|
118
|
+
// regardless of the error, we are done
|
|
119
|
+
onListen()
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
const secondaryServer = getServerInstance(serverOpts, httpHandler)
|
|
125
|
+
const closeSecondary = () => { secondaryServer.close(() => {}) }
|
|
126
|
+
mainServer.on('unref', closeSecondary)
|
|
127
|
+
mainServer.on('close', closeSecondary)
|
|
128
|
+
mainServer.on('error', closeSecondary)
|
|
129
|
+
listenCallback.call(this, secondaryServer, secondaryOpts)()
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// no extra bindings are necessary
|
|
134
|
+
if (binding === 0) {
|
|
135
|
+
onListen()
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// in test files we are using unref so we need to propagate the unref event
|
|
140
|
+
// to the secondary servers. It is valid only when the user is
|
|
141
|
+
// listening on localhost
|
|
142
|
+
const originUnref = mainServer.unref
|
|
143
|
+
/* istanbul ignore next */
|
|
144
|
+
mainServer.unref = function () {
|
|
145
|
+
originUnref.call(mainServer)
|
|
146
|
+
mainServer.emit('unref')
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function listenCallback (server, listenOptions) {
|
|
152
|
+
const wrap = (err) => {
|
|
153
|
+
server.removeListener('error', wrap)
|
|
154
|
+
if (!err) {
|
|
155
|
+
const address = logServerAddress.call(this, server)
|
|
156
|
+
listenOptions.cb(null, address)
|
|
157
|
+
} else {
|
|
158
|
+
this[kState].listening = false
|
|
159
|
+
listenOptions.cb(err, null)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return (err) => {
|
|
164
|
+
if (err != null) return listenOptions.cb(err)
|
|
165
|
+
|
|
166
|
+
if (this[kState].listening && this[kState].closing) {
|
|
167
|
+
return listenOptions.cb(new FST_ERR_REOPENED_CLOSE_SERVER(), null)
|
|
168
|
+
} else if (this[kState].listening) {
|
|
169
|
+
return listenOptions.cb(new FST_ERR_REOPENED_SERVER(), null)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
server.once('error', wrap)
|
|
173
|
+
server.listen(listenOptions, wrap)
|
|
174
|
+
|
|
175
|
+
this[kState].listening = true
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function listenPromise (server, listenOptions) {
|
|
180
|
+
if (this[kState].listening && this[kState].closing) {
|
|
181
|
+
return Promise.reject(new FST_ERR_REOPENED_CLOSE_SERVER())
|
|
182
|
+
} else if (this[kState].listening) {
|
|
183
|
+
return Promise.reject(new FST_ERR_REOPENED_SERVER())
|
|
184
|
+
}
|
|
13
185
|
|
|
186
|
+
return this.ready().then(() => {
|
|
187
|
+
let errEventHandler
|
|
188
|
+
const errEvent = new Promise((resolve, reject) => {
|
|
189
|
+
errEventHandler = (err) => {
|
|
190
|
+
this[kState].listening = false
|
|
191
|
+
reject(err)
|
|
192
|
+
}
|
|
193
|
+
server.once('error', errEventHandler)
|
|
194
|
+
})
|
|
195
|
+
const listen = new Promise((resolve, reject) => {
|
|
196
|
+
server.listen(listenOptions, () => {
|
|
197
|
+
server.removeListener('error', errEventHandler)
|
|
198
|
+
resolve(logServerAddress.call(this, server))
|
|
199
|
+
})
|
|
200
|
+
// we set it afterwards because listen can throw
|
|
201
|
+
this[kState].listening = true
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
return Promise.race([
|
|
205
|
+
errEvent, // e.g invalid port range error is always emitted before the server listening
|
|
206
|
+
listen
|
|
207
|
+
])
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function getServerInstance (options, httpHandler) {
|
|
14
212
|
let server = null
|
|
15
213
|
if (options.serverFactory) {
|
|
16
214
|
server = options.serverFactory(httpHandler, options)
|
|
@@ -41,123 +239,53 @@ function createServer (options, httpHandler) {
|
|
|
41
239
|
if (!options.serverFactory) {
|
|
42
240
|
server.setTimeout(options.connectionTimeout)
|
|
43
241
|
}
|
|
242
|
+
return server
|
|
243
|
+
}
|
|
44
244
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const normalizeListenArgs = (args) => {
|
|
50
|
-
if (args.length === 0) {
|
|
51
|
-
return { port: 0, host: 'localhost' }
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined
|
|
55
|
-
const options = { cb }
|
|
56
|
-
|
|
57
|
-
const firstArg = args[0]
|
|
58
|
-
const argsLength = args.length
|
|
59
|
-
const lastArg = args[argsLength - 1]
|
|
60
|
-
/* Deal with listen (options) || (handle[, backlog]) */
|
|
61
|
-
if (typeof firstArg === 'object' && firstArg !== null) {
|
|
62
|
-
options.backlog = argsLength > 1 ? lastArg : undefined
|
|
63
|
-
Object.assign(options, firstArg)
|
|
64
|
-
} else if (typeof firstArg === 'string' && isNaN(firstArg)) {
|
|
65
|
-
/* Deal with listen (pipe[, backlog]) */
|
|
66
|
-
options.path = firstArg
|
|
67
|
-
options.backlog = argsLength > 1 ? lastArg : undefined
|
|
68
|
-
} else {
|
|
69
|
-
/* Deal with listen ([port[, host[, backlog]]]) */
|
|
70
|
-
options.port = argsLength >= 1 && firstArg ? firstArg : 0
|
|
71
|
-
// This will listen to what localhost is.
|
|
72
|
-
// It can be 127.0.0.1 or ::1, depending on the operating system.
|
|
73
|
-
// Fixes https://github.com/fastify/fastify/issues/1022.
|
|
74
|
-
options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost'
|
|
75
|
-
options.backlog = argsLength >= 3 ? args[2] : undefined
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return options
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const listenOptions = normalizeListenArgs(Array.from(arguments))
|
|
82
|
-
const cb = listenOptions.cb
|
|
83
|
-
|
|
84
|
-
const wrap = err => {
|
|
85
|
-
server.removeListener('error', wrap)
|
|
86
|
-
if (!err) {
|
|
87
|
-
const address = logServerAddress()
|
|
88
|
-
cb(null, address)
|
|
89
|
-
} else {
|
|
90
|
-
this[kState].listening = false
|
|
91
|
-
cb(err, null)
|
|
92
|
-
}
|
|
93
|
-
}
|
|
245
|
+
function normalizeListenArgs (args) {
|
|
246
|
+
if (args.length === 0) {
|
|
247
|
+
return { port: 0, host: 'localhost' }
|
|
248
|
+
}
|
|
94
249
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return Promise.reject(new FST_ERR_REOPENED_CLOSE_SERVER())
|
|
98
|
-
} else if (this[kState].listening) {
|
|
99
|
-
return Promise.reject(new FST_ERR_REOPENED_SERVER())
|
|
100
|
-
}
|
|
250
|
+
const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined
|
|
251
|
+
const options = { cb }
|
|
101
252
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
})
|
|
253
|
+
const firstArg = args[0]
|
|
254
|
+
const argsLength = args.length
|
|
255
|
+
const lastArg = args[argsLength - 1]
|
|
256
|
+
if (typeof firstArg === 'string' && isNaN(firstArg)) {
|
|
257
|
+
/* Deal with listen (pipe[, backlog]) */
|
|
258
|
+
options.path = firstArg
|
|
259
|
+
options.backlog = argsLength > 1 ? lastArg : undefined
|
|
260
|
+
} else {
|
|
261
|
+
/* Deal with listen ([port[, host[, backlog]]]) */
|
|
262
|
+
options.port = argsLength >= 1 && Number.isInteger(firstArg) ? firstArg : 0
|
|
263
|
+
// This will listen to what localhost is.
|
|
264
|
+
// It can be 127.0.0.1 or ::1, depending on the operating system.
|
|
265
|
+
// Fixes https://github.com/fastify/fastify/issues/1022.
|
|
266
|
+
options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost'
|
|
267
|
+
options.backlog = argsLength >= 3 ? args[2] : undefined
|
|
268
|
+
}
|
|
119
269
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
listen
|
|
123
|
-
])
|
|
124
|
-
})
|
|
125
|
-
}
|
|
270
|
+
return options
|
|
271
|
+
}
|
|
126
272
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
/* istanbul ignore next */
|
|
139
|
-
address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address
|
|
140
|
-
this.log.info('Server listening at ' + address)
|
|
141
|
-
return address
|
|
273
|
+
function logServerAddress (server) {
|
|
274
|
+
let address = server.address()
|
|
275
|
+
const isUnixSocket = typeof address === 'string'
|
|
276
|
+
/* istanbul ignore next */
|
|
277
|
+
if (!isUnixSocket) {
|
|
278
|
+
if (address.address.indexOf(':') === -1) {
|
|
279
|
+
address = address.address + ':' + address.port
|
|
280
|
+
} else {
|
|
281
|
+
address = '[' + address.address + ']:' + address.port
|
|
142
282
|
}
|
|
143
|
-
|
|
144
|
-
if (cb === undefined) return listenPromise(listenOptions)
|
|
145
|
-
|
|
146
|
-
this.ready(err => {
|
|
147
|
-
if (err != null) return cb(err)
|
|
148
|
-
|
|
149
|
-
if (this[kState].listening && this[kState].closing) {
|
|
150
|
-
return cb(new FST_ERR_REOPENED_CLOSE_SERVER(), null)
|
|
151
|
-
} else if (this[kState].listening) {
|
|
152
|
-
return cb(new FST_ERR_REOPENED_SERVER(), null)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
server.once('error', wrap)
|
|
156
|
-
server.listen(listenOptions, wrap)
|
|
157
|
-
|
|
158
|
-
this[kState].listening = true
|
|
159
|
-
})
|
|
160
283
|
}
|
|
284
|
+
/* istanbul ignore next */
|
|
285
|
+
address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address
|
|
286
|
+
|
|
287
|
+
this.log.info('Server listening at ' + address)
|
|
288
|
+
return address
|
|
161
289
|
}
|
|
162
290
|
|
|
163
291
|
function http2 () {
|
|
@@ -177,5 +305,3 @@ function sessionTimeout (timeout) {
|
|
|
177
305
|
function close () {
|
|
178
306
|
this.close()
|
|
179
307
|
}
|
|
180
|
-
|
|
181
|
-
module.exports = { createServer }
|
package/lib/symbols.js
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
const keys = {
|
|
4
4
|
kAvvioBoot: Symbol('fastify.avvioBoot'),
|
|
5
5
|
kChildren: Symbol('fastify.children'),
|
|
6
|
+
kServerBindings: Symbol('fastify.serverBindings'),
|
|
6
7
|
kBodyLimit: Symbol('fastify.bodyLimit'),
|
|
7
8
|
kRoutePrefix: Symbol('fastify.routePrefix'),
|
|
8
9
|
kLogLevel: Symbol('fastify.logLevel'),
|
|
9
10
|
kLogSerializers: Symbol('fastify.logSerializers'),
|
|
10
11
|
kHooks: Symbol('fastify.hooks'),
|
|
11
|
-
kHooksDeprecatedPreParsing: Symbol('fastify.hooks.DeprecatedPreParsing'),
|
|
12
12
|
kSchemaController: Symbol('fastify.schemaController'),
|
|
13
13
|
kSchemaHeaders: Symbol('headers-schema'),
|
|
14
14
|
kSchemaParams: Symbol('params-schema'),
|
|
@@ -30,10 +30,11 @@ const keys = {
|
|
|
30
30
|
kReplySerializer: Symbol('fastify.reply.serializer'),
|
|
31
31
|
kReplyIsError: Symbol('fastify.reply.isError'),
|
|
32
32
|
kReplyHeaders: Symbol('fastify.reply.headers'),
|
|
33
|
+
kReplyTrailers: Symbol('fastify.reply.trailers'),
|
|
33
34
|
kReplyHasStatusCode: Symbol('fastify.reply.hasStatusCode'),
|
|
34
|
-
|
|
35
|
-
kReplySentOverwritten: Symbol('fastify.reply.sentOverwritten'),
|
|
35
|
+
kReplyHijacked: Symbol('fastify.reply.hijacked'),
|
|
36
36
|
kReplyStartTime: Symbol('fastify.reply.startTime'),
|
|
37
|
+
kReplyNextErrorHandler: Symbol('fastify.reply.nextErrorHandler'),
|
|
37
38
|
kReplyEndTime: Symbol('fastify.reply.endTime'),
|
|
38
39
|
kReplyErrorHandlerCalled: Symbol('fastify.reply.errorHandlerCalled'),
|
|
39
40
|
kReplyIsRunningOnErrorHook: Symbol('fastify.reply.isRunningOnErrorHook'),
|
|
@@ -45,6 +46,7 @@ const keys = {
|
|
|
45
46
|
// This symbol is only meant to be used for fastify tests and should not be used for any other purpose
|
|
46
47
|
kTestInternals: Symbol('fastify.testInternals'),
|
|
47
48
|
kErrorHandler: Symbol('fastify.errorHandler'),
|
|
49
|
+
kHasBeenDecorated: Symbol('fastify.hasBeenDecorated'),
|
|
48
50
|
kKeepAliveConnections: Symbol('fastify.keepAliveConnections')
|
|
49
51
|
}
|
|
50
52
|
|
package/lib/validation.js
CHANGED
|
@@ -27,13 +27,14 @@ function compileSchemasForSerialization (context, compile) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function compileSchemasForValidation (context, compile) {
|
|
30
|
-
|
|
30
|
+
const { schema } = context
|
|
31
|
+
if (!schema) {
|
|
31
32
|
return
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
const { method, url } = context.config || {}
|
|
35
36
|
|
|
36
|
-
const headers =
|
|
37
|
+
const headers = schema.headers
|
|
37
38
|
if (headers && Object.getPrototypeOf(headers) !== Object.prototype) {
|
|
38
39
|
// do not mess with non-literals, e.g. Joi schemas
|
|
39
40
|
context[headersSchema] = compile({ schema: headers, method, url, httpPart: 'headers' })
|
|
@@ -54,21 +55,22 @@ function compileSchemasForValidation (context, compile) {
|
|
|
54
55
|
context[headersSchema] = compile({ schema: headersSchemaLowerCase, method, url, httpPart: 'headers' })
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
if (
|
|
58
|
-
context[bodySchema] = compile({ schema:
|
|
58
|
+
if (schema.body) {
|
|
59
|
+
context[bodySchema] = compile({ schema: schema.body, method, url, httpPart: 'body' })
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
if (
|
|
62
|
-
context[querystringSchema] = compile({ schema:
|
|
62
|
+
if (schema.querystring) {
|
|
63
|
+
context[querystringSchema] = compile({ schema: schema.querystring, method, url, httpPart: 'querystring' })
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
if (
|
|
66
|
-
context[paramsSchema] = compile({ schema:
|
|
66
|
+
if (schema.params) {
|
|
67
|
+
context[paramsSchema] = compile({ schema: schema.params, method, url, httpPart: 'params' })
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
function validateParam (validatorFunction, request, paramName) {
|
|
71
|
-
const
|
|
72
|
+
const isUndefined = request[paramName] === undefined
|
|
73
|
+
const ret = validatorFunction && validatorFunction(isUndefined ? null : request[paramName])
|
|
72
74
|
if (ret === false) return validatorFunction.errors
|
|
73
75
|
if (ret && ret.error) return ret.error
|
|
74
76
|
if (ret && ret.value) request[paramName] = ret.value
|
package/lib/warnings.js
CHANGED
|
@@ -4,21 +4,9 @@ const warning = require('process-warning')()
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Deprecation codes:
|
|
7
|
-
* - FSTDEP001
|
|
8
|
-
* - FSTDEP002
|
|
9
|
-
* - FSTDEP003
|
|
10
|
-
* - FSTDEP004
|
|
11
7
|
* - FSTDEP005
|
|
12
8
|
*/
|
|
13
9
|
|
|
14
|
-
warning.create('FastifyDeprecation', 'FSTDEP001', 'You are accessing the Node.js core request object via "request.req", Use "request.raw" instead.')
|
|
15
|
-
|
|
16
|
-
warning.create('FastifyDeprecation', 'FSTDEP002', 'You are accessing the Node.js core response object via "reply.res", Use "reply.raw" instead.')
|
|
17
|
-
|
|
18
|
-
warning.create('FastifyDeprecation', 'FSTDEP003', 'You are using the legacy Content Type Parser function signature. Use the one suggested in the documentation instead.')
|
|
19
|
-
|
|
20
|
-
warning.create('FastifyDeprecation', 'FSTDEP004', 'You are using the legacy preParsing hook signature. Use the one suggested in the documentation instead.')
|
|
21
|
-
|
|
22
10
|
warning.create('FastifyDeprecation', 'FSTDEP005', 'You are accessing the deprecated "request.connection" property. Use "request.socket" instead.')
|
|
23
11
|
|
|
24
12
|
warning.create('FastifyDeprecation', 'FSTDEP006', 'You are decorating Request/Reply with a reference type. This reference is shared amongst all requests. Use onRequest hook instead. Property: %s')
|
|
@@ -29,4 +17,8 @@ warning.create('FastifyDeprecation', 'FSTDEP008', 'You are using route constrain
|
|
|
29
17
|
|
|
30
18
|
warning.create('FastifyDeprecation', 'FSTDEP009', 'You are using a custom route versioning strategy via the server { versioning: "..." } option, use { constraints: { version: "..." } } option instead.')
|
|
31
19
|
|
|
20
|
+
warning.create('FastifyDeprecation', 'FSTDEP010', 'Modifying the "reply.sent" property is deprecated. Use the "reply.hijack()" method instead.')
|
|
21
|
+
|
|
22
|
+
warning.create('FastifyDeprecation', 'FSTDEP011', 'Variadic listen method is deprecated. Please use ".listen(optionsObject)" instead. The variadic signature will be removed in `fastify@5`.')
|
|
23
|
+
|
|
32
24
|
module.exports = warning
|
package/lib/wrapThenable.js
CHANGED
|
@@ -2,40 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
kReplyIsError,
|
|
5
|
-
|
|
6
|
-
kReplySentOverwritten
|
|
5
|
+
kReplyHijacked
|
|
7
6
|
} = require('./symbols')
|
|
8
7
|
|
|
9
|
-
const { FST_ERR_PROMISE_NOT_FULFILLED } = require('./errors')
|
|
10
|
-
|
|
11
8
|
function wrapThenable (thenable, reply) {
|
|
12
9
|
thenable.then(function (payload) {
|
|
13
|
-
if (reply[
|
|
10
|
+
if (reply[kReplyHijacked] === true) {
|
|
14
11
|
return
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
// this is for async functions that
|
|
18
15
|
// are using reply.send directly
|
|
19
|
-
if (payload !== undefined ||
|
|
16
|
+
if (payload !== undefined || reply.sent === false) {
|
|
20
17
|
// we use a try-catch internally to avoid adding a catch to another
|
|
21
18
|
// promise, increase promise perf by 10%
|
|
22
19
|
try {
|
|
23
20
|
reply.send(payload)
|
|
24
21
|
} catch (err) {
|
|
25
|
-
reply[kReplySent] = false
|
|
26
22
|
reply[kReplyIsError] = true
|
|
27
23
|
reply.send(err)
|
|
28
24
|
}
|
|
29
|
-
} else if (reply[kReplySent] === false) {
|
|
30
|
-
reply.log.error({ err: new FST_ERR_PROMISE_NOT_FULFILLED() }, "Promise may not be fulfilled with 'undefined' when statusCode is not 204")
|
|
31
25
|
}
|
|
32
26
|
}, function (err) {
|
|
33
|
-
if (reply
|
|
27
|
+
if (reply.sent === true) {
|
|
34
28
|
reply.log.error({ err }, 'Promise errored, but reply.sent = true was set')
|
|
35
29
|
return
|
|
36
30
|
}
|
|
37
31
|
|
|
38
|
-
reply[kReplySent] = false
|
|
39
32
|
reply[kReplyIsError] = true
|
|
40
33
|
reply.send(err)
|
|
41
34
|
})
|