1 | 'use strict'
|
2 |
|
3 | const FindMyWay = require('find-my-way')
|
4 | const Context = require('./context')
|
5 | const handleRequest = require('./handleRequest')
|
6 | const { onRequestAbortHookRunner, lifecycleHooks, preParsingHookRunner, onTimeoutHookRunner, onRequestHookRunner } = require('./hooks')
|
7 | const { supportedMethods } = require('./httpMethods')
|
8 | const { normalizeSchema } = require('./schemas')
|
9 | const { parseHeadOnSendHandlers } = require('./headRoute')
|
10 | const {
|
11 | FSTDEP007,
|
12 | FSTDEP008,
|
13 | FSTDEP014
|
14 | } = require('./warnings')
|
15 |
|
16 | const {
|
17 | compileSchemasForValidation,
|
18 | compileSchemasForSerialization
|
19 | } = require('./validation')
|
20 |
|
21 | const {
|
22 | FST_ERR_SCH_VALIDATION_BUILD,
|
23 | FST_ERR_SCH_SERIALIZATION_BUILD,
|
24 | FST_ERR_DEFAULT_ROUTE_INVALID_TYPE,
|
25 | FST_ERR_DUPLICATED_ROUTE,
|
26 | FST_ERR_INVALID_URL,
|
27 | FST_ERR_HOOK_INVALID_HANDLER,
|
28 | FST_ERR_ROUTE_OPTIONS_NOT_OBJ,
|
29 | FST_ERR_ROUTE_DUPLICATED_HANDLER,
|
30 | FST_ERR_ROUTE_HANDLER_NOT_FN,
|
31 | FST_ERR_ROUTE_MISSING_HANDLER,
|
32 | FST_ERR_ROUTE_METHOD_NOT_SUPPORTED,
|
33 | FST_ERR_ROUTE_METHOD_INVALID,
|
34 | FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED,
|
35 | FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT,
|
36 | FST_ERR_HOOK_INVALID_ASYNC_HANDLER
|
37 | } = require('./errors')
|
38 |
|
39 | const {
|
40 | kRoutePrefix,
|
41 | kLogLevel,
|
42 | kLogSerializers,
|
43 | kHooks,
|
44 | kSchemaController,
|
45 | kOptions,
|
46 | kReplySerializerDefault,
|
47 | kReplyIsError,
|
48 | kRequestPayloadStream,
|
49 | kDisableRequestLogging,
|
50 | kSchemaErrorFormatter,
|
51 | kErrorHandler,
|
52 | kHasBeenDecorated,
|
53 | kRequestAcceptVersion,
|
54 | kRouteByFastify,
|
55 | kRouteContext
|
56 | } = require('./symbols.js')
|
57 | const { buildErrorHandler } = require('./error-handler')
|
58 | const { createChildLogger } = require('./logger')
|
59 | const { getGenReqId } = require('./reqIdGenFactory.js')
|
60 |
|
61 | function buildRouting (options) {
|
62 | const router = FindMyWay(options.config)
|
63 |
|
64 | let avvio
|
65 | let fourOhFour
|
66 | let logger
|
67 | let hasLogger
|
68 | let setupResponseListeners
|
69 | let throwIfAlreadyStarted
|
70 | let disableRequestLogging
|
71 | let ignoreTrailingSlash
|
72 | let ignoreDuplicateSlashes
|
73 | let return503OnClosing
|
74 | let globalExposeHeadRoutes
|
75 | let validateHTTPVersion
|
76 | let keepAliveConnections
|
77 |
|
78 | let closing = false
|
79 |
|
80 | return {
|
81 | |
82 |
|
83 |
|
84 |
|
85 | setup (options, fastifyArgs) {
|
86 | avvio = fastifyArgs.avvio
|
87 | fourOhFour = fastifyArgs.fourOhFour
|
88 | logger = fastifyArgs.logger
|
89 | hasLogger = fastifyArgs.hasLogger
|
90 | setupResponseListeners = fastifyArgs.setupResponseListeners
|
91 | throwIfAlreadyStarted = fastifyArgs.throwIfAlreadyStarted
|
92 | validateHTTPVersion = fastifyArgs.validateHTTPVersion
|
93 |
|
94 | globalExposeHeadRoutes = options.exposeHeadRoutes
|
95 | disableRequestLogging = options.disableRequestLogging
|
96 | ignoreTrailingSlash = options.ignoreTrailingSlash
|
97 | ignoreDuplicateSlashes = options.ignoreDuplicateSlashes
|
98 | return503OnClosing = Object.prototype.hasOwnProperty.call(options, 'return503OnClosing') ? options.return503OnClosing : true
|
99 | keepAliveConnections = fastifyArgs.keepAliveConnections
|
100 | },
|
101 | routing: router.lookup.bind(router),
|
102 | route,
|
103 | hasRoute,
|
104 | prepareRoute,
|
105 | getDefaultRoute: function () {
|
106 | FSTDEP014()
|
107 | return router.defaultRoute
|
108 | },
|
109 | setDefaultRoute: function (defaultRoute) {
|
110 | FSTDEP014()
|
111 | if (typeof defaultRoute !== 'function') {
|
112 | throw new FST_ERR_DEFAULT_ROUTE_INVALID_TYPE()
|
113 | }
|
114 |
|
115 | router.defaultRoute = defaultRoute
|
116 | },
|
117 | routeHandler,
|
118 | closeRoutes: () => { closing = true },
|
119 | printRoutes: router.prettyPrint.bind(router),
|
120 | addConstraintStrategy,
|
121 | hasConstraintStrategy,
|
122 | isAsyncConstraint,
|
123 | findRoute
|
124 | }
|
125 |
|
126 | function addConstraintStrategy (strategy) {
|
127 | throwIfAlreadyStarted('Cannot add constraint strategy!')
|
128 | return router.addConstraintStrategy(strategy)
|
129 | }
|
130 |
|
131 | function hasConstraintStrategy (strategyName) {
|
132 | return router.hasConstraintStrategy(strategyName)
|
133 | }
|
134 |
|
135 | function isAsyncConstraint () {
|
136 | return router.constrainer.asyncStrategiesInUse.size > 0
|
137 | }
|
138 |
|
139 |
|
140 | function prepareRoute ({ method, url, options, handler, isFastify }) {
|
141 | if (typeof url !== 'string') {
|
142 | throw new FST_ERR_INVALID_URL(typeof url)
|
143 | }
|
144 |
|
145 | if (!handler && typeof options === 'function') {
|
146 | handler = options
|
147 | options = {}
|
148 | } else if (handler && typeof handler === 'function') {
|
149 | if (Object.prototype.toString.call(options) !== '[object Object]') {
|
150 | throw new FST_ERR_ROUTE_OPTIONS_NOT_OBJ(method, url)
|
151 | } else if (options.handler) {
|
152 | if (typeof options.handler === 'function') {
|
153 | throw new FST_ERR_ROUTE_DUPLICATED_HANDLER(method, url)
|
154 | } else {
|
155 | throw new FST_ERR_ROUTE_HANDLER_NOT_FN(method, url)
|
156 | }
|
157 | }
|
158 | }
|
159 |
|
160 | options = Object.assign({}, options, {
|
161 | method,
|
162 | url,
|
163 | path: url,
|
164 | handler: handler || (options && options.handler)
|
165 | })
|
166 |
|
167 | return route.call(this, { options, isFastify })
|
168 | }
|
169 |
|
170 | function hasRoute ({ options }) {
|
171 | const normalizedMethod = options.method?.toUpperCase() ?? ''
|
172 | return findRoute({
|
173 | ...options,
|
174 | method: normalizedMethod
|
175 | }) !== null
|
176 | }
|
177 |
|
178 | function findRoute (options) {
|
179 | const route = router.find(
|
180 | options.method,
|
181 | options.url || '',
|
182 | options.constraints
|
183 | )
|
184 | if (route) {
|
185 |
|
186 |
|
187 |
|
188 | return {
|
189 | handler: route.handler,
|
190 | params: route.params,
|
191 | searchParams: route.searchParams
|
192 | }
|
193 | } else {
|
194 | return null
|
195 | }
|
196 | }
|
197 |
|
198 | |
199 |
|
200 |
|
201 |
|
202 | function route ({ options, isFastify }) {
|
203 |
|
204 | const opts = { ...options }
|
205 |
|
206 | const { exposeHeadRoute } = opts
|
207 | const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null
|
208 | const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes
|
209 |
|
210 | const isGetRoute = opts.method === 'GET' ||
|
211 | (Array.isArray(opts.method) && opts.method.includes('GET'))
|
212 | const isHeadRoute = opts.method === 'HEAD' ||
|
213 | (Array.isArray(opts.method) && opts.method.includes('HEAD'))
|
214 |
|
215 |
|
216 | const headOpts = shouldExposeHead && isGetRoute ? { ...options } : null
|
217 |
|
218 | throwIfAlreadyStarted('Cannot add route!')
|
219 |
|
220 | const path = opts.url || opts.path || ''
|
221 |
|
222 | if (Array.isArray(opts.method)) {
|
223 |
|
224 | for (var i = 0; i < opts.method.length; ++i) {
|
225 | opts.method[i] = normalizeAndValidateMethod(opts.method[i])
|
226 | validateSchemaBodyOption(opts.method[i], path, opts.schema)
|
227 | }
|
228 | } else {
|
229 | opts.method = normalizeAndValidateMethod(opts.method)
|
230 | validateSchemaBodyOption(opts.method, path, opts.schema)
|
231 | }
|
232 |
|
233 | if (!opts.handler) {
|
234 | throw new FST_ERR_ROUTE_MISSING_HANDLER(opts.method, path)
|
235 | }
|
236 |
|
237 | if (opts.errorHandler !== undefined && typeof opts.errorHandler !== 'function') {
|
238 | throw new FST_ERR_ROUTE_HANDLER_NOT_FN(opts.method, path)
|
239 | }
|
240 |
|
241 | validateBodyLimitOption(opts.bodyLimit)
|
242 |
|
243 | const prefix = this[kRoutePrefix]
|
244 |
|
245 | if (path === '/' && prefix.length > 0 && opts.method !== 'HEAD') {
|
246 | switch (opts.prefixTrailingSlash) {
|
247 | case 'slash':
|
248 | addNewRoute.call(this, { path, isFastify })
|
249 | break
|
250 | case 'no-slash':
|
251 | addNewRoute.call(this, { path: '', isFastify })
|
252 | break
|
253 | case 'both':
|
254 | default:
|
255 | addNewRoute.call(this, { path: '', isFastify })
|
256 |
|
257 | if (ignoreTrailingSlash !== true && (ignoreDuplicateSlashes !== true || !prefix.endsWith('/'))) {
|
258 | addNewRoute.call(this, { path, prefixing: true, isFastify })
|
259 | }
|
260 | }
|
261 | } else if (path[0] === '/' && prefix.endsWith('/')) {
|
262 |
|
263 | addNewRoute.call(this, { path: path.slice(1), isFastify })
|
264 | } else {
|
265 | addNewRoute.call(this, { path, isFastify })
|
266 | }
|
267 |
|
268 |
|
269 | return this
|
270 |
|
271 | function addNewRoute ({ path, prefixing = false, isFastify = false }) {
|
272 | const url = prefix + path
|
273 |
|
274 | opts.url = url
|
275 | opts.path = url
|
276 | opts.routePath = path
|
277 | opts.prefix = prefix
|
278 | opts.logLevel = opts.logLevel || this[kLogLevel]
|
279 |
|
280 | if (this[kLogSerializers] || opts.logSerializers) {
|
281 | opts.logSerializers = Object.assign(Object.create(this[kLogSerializers]), opts.logSerializers)
|
282 | }
|
283 |
|
284 | if (opts.attachValidation == null) {
|
285 | opts.attachValidation = false
|
286 | }
|
287 |
|
288 | if (prefixing === false) {
|
289 |
|
290 | for (const hook of this[kHooks].onRoute) {
|
291 | hook.call(this, opts)
|
292 | }
|
293 | }
|
294 |
|
295 | for (const hook of lifecycleHooks) {
|
296 | if (opts && hook in opts) {
|
297 | if (Array.isArray(opts[hook])) {
|
298 | for (const func of opts[hook]) {
|
299 | if (typeof func !== 'function') {
|
300 | throw new FST_ERR_HOOK_INVALID_HANDLER(hook, Object.prototype.toString.call(func))
|
301 | }
|
302 |
|
303 | if (hook === 'onSend' || hook === 'preSerialization' || hook === 'onError' || hook === 'preParsing') {
|
304 | if (func.constructor.name === 'AsyncFunction' && func.length === 4) {
|
305 | throw new FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
|
306 | }
|
307 | } else if (hook === 'onRequestAbort') {
|
308 | if (func.constructor.name === 'AsyncFunction' && func.length !== 1) {
|
309 | throw new FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
|
310 | }
|
311 | } else {
|
312 | if (func.constructor.name === 'AsyncFunction' && func.length === 3) {
|
313 | throw new FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
|
314 | }
|
315 | }
|
316 | }
|
317 | } else if (opts[hook] !== undefined && typeof opts[hook] !== 'function') {
|
318 | throw new FST_ERR_HOOK_INVALID_HANDLER(hook, Object.prototype.toString.call(opts[hook]))
|
319 | }
|
320 | }
|
321 | }
|
322 |
|
323 | const constraints = opts.constraints || {}
|
324 | const config = {
|
325 | ...opts.config,
|
326 | url,
|
327 | method: opts.method
|
328 | }
|
329 |
|
330 | const context = new Context({
|
331 | schema: opts.schema,
|
332 | handler: opts.handler.bind(this),
|
333 | config,
|
334 | errorHandler: opts.errorHandler,
|
335 | childLoggerFactory: opts.childLoggerFactory,
|
336 | bodyLimit: opts.bodyLimit,
|
337 | logLevel: opts.logLevel,
|
338 | logSerializers: opts.logSerializers,
|
339 | attachValidation: opts.attachValidation,
|
340 | schemaErrorFormatter: opts.schemaErrorFormatter,
|
341 | replySerializer: this[kReplySerializerDefault],
|
342 | validatorCompiler: opts.validatorCompiler,
|
343 | serializerCompiler: opts.serializerCompiler,
|
344 | exposeHeadRoute: shouldExposeHead,
|
345 | prefixTrailingSlash: (opts.prefixTrailingSlash || 'both'),
|
346 | server: this,
|
347 | isFastify
|
348 | })
|
349 |
|
350 | if (opts.version) {
|
351 | FSTDEP008()
|
352 | constraints.version = opts.version
|
353 | }
|
354 |
|
355 | const headHandler = router.findRoute('HEAD', opts.url, constraints)
|
356 | const hasHEADHandler = headHandler !== null
|
357 |
|
358 |
|
359 | if (isHeadRoute && hasHEADHandler && !context[kRouteByFastify] && headHandler.store[kRouteByFastify]) {
|
360 | router.off('HEAD', opts.url, constraints)
|
361 | }
|
362 |
|
363 | try {
|
364 | router.on(opts.method, opts.url, { constraints }, routeHandler, context)
|
365 | } catch (error) {
|
366 |
|
367 |
|
368 | if (!context[kRouteByFastify]) {
|
369 | const isDuplicatedRoute = error.message.includes(`Method '${opts.method}' already declared for route '${opts.url}'`)
|
370 | if (isDuplicatedRoute) {
|
371 | throw new FST_ERR_DUPLICATED_ROUTE(opts.method, opts.url)
|
372 | }
|
373 |
|
374 | throw error
|
375 | }
|
376 | }
|
377 |
|
378 | this.after((notHandledErr, done) => {
|
379 |
|
380 | context.errorHandler = opts.errorHandler ? buildErrorHandler(this[kErrorHandler], opts.errorHandler) : this[kErrorHandler]
|
381 | context._parserOptions.limit = opts.bodyLimit || null
|
382 | context.logLevel = opts.logLevel
|
383 | context.logSerializers = opts.logSerializers
|
384 | context.attachValidation = opts.attachValidation
|
385 | context[kReplySerializerDefault] = this[kReplySerializerDefault]
|
386 | context.schemaErrorFormatter = opts.schemaErrorFormatter || this[kSchemaErrorFormatter] || context.schemaErrorFormatter
|
387 |
|
388 |
|
389 | avvio.once('preReady', () => {
|
390 | for (const hook of lifecycleHooks) {
|
391 | const toSet = this[kHooks][hook]
|
392 | .concat(opts[hook] || [])
|
393 | .map(h => h.bind(this))
|
394 | context[hook] = toSet.length ? toSet : null
|
395 | }
|
396 |
|
397 |
|
398 | while (!context.Request[kHasBeenDecorated] && context.Request.parent) {
|
399 | context.Request = context.Request.parent
|
400 | }
|
401 | while (!context.Reply[kHasBeenDecorated] && context.Reply.parent) {
|
402 | context.Reply = context.Reply.parent
|
403 | }
|
404 |
|
405 |
|
406 |
|
407 | fourOhFour.setContext(this, context)
|
408 |
|
409 | if (opts.schema) {
|
410 | context.schema = normalizeSchema(context.schema, this.initialConfig)
|
411 |
|
412 | const schemaController = this[kSchemaController]
|
413 | if (!opts.validatorCompiler && (opts.schema.body || opts.schema.headers || opts.schema.querystring || opts.schema.params)) {
|
414 | schemaController.setupValidator(this[kOptions])
|
415 | }
|
416 | try {
|
417 | const isCustom = typeof opts?.validatorCompiler === 'function' || schemaController.isCustomValidatorCompiler
|
418 | compileSchemasForValidation(context, opts.validatorCompiler || schemaController.validatorCompiler, isCustom)
|
419 | } catch (error) {
|
420 | throw new FST_ERR_SCH_VALIDATION_BUILD(opts.method, url, error.message)
|
421 | }
|
422 |
|
423 | if (opts.schema.response && !opts.serializerCompiler) {
|
424 | schemaController.setupSerializer(this[kOptions])
|
425 | }
|
426 | try {
|
427 | compileSchemasForSerialization(context, opts.serializerCompiler || schemaController.serializerCompiler)
|
428 | } catch (error) {
|
429 | throw new FST_ERR_SCH_SERIALIZATION_BUILD(opts.method, url, error.message)
|
430 | }
|
431 | }
|
432 | })
|
433 |
|
434 | done(notHandledErr)
|
435 | })
|
436 |
|
437 |
|
438 |
|
439 |
|
440 | if (shouldExposeHead && isGetRoute && !isHeadRoute && !hasHEADHandler) {
|
441 | const onSendHandlers = parseHeadOnSendHandlers(headOpts.onSend)
|
442 | prepareRoute.call(this, { method: 'HEAD', url: path, options: { ...headOpts, onSend: onSendHandlers }, isFastify: true })
|
443 | } else if (hasHEADHandler && exposeHeadRoute) {
|
444 | FSTDEP007()
|
445 | }
|
446 | }
|
447 | }
|
448 |
|
449 |
|
450 | function routeHandler (req, res, params, context, query) {
|
451 | const id = getGenReqId(context.server, req)
|
452 |
|
453 | const loggerOpts = {
|
454 | level: context.logLevel
|
455 | }
|
456 |
|
457 | if (context.logSerializers) {
|
458 | loggerOpts.serializers = context.logSerializers
|
459 | }
|
460 | const childLogger = createChildLogger(context, logger, req, id, loggerOpts)
|
461 | childLogger[kDisableRequestLogging] = disableRequestLogging
|
462 |
|
463 |
|
464 | if (!validateHTTPVersion(req.httpVersion)) {
|
465 | childLogger.info({ res: { statusCode: 505 } }, 'request aborted - invalid HTTP version')
|
466 | const message = '{"error":"HTTP Version Not Supported","message":"HTTP Version Not Supported","statusCode":505}'
|
467 | const headers = {
|
468 | 'Content-Type': 'application/json',
|
469 | 'Content-Length': message.length
|
470 | }
|
471 | res.writeHead(505, headers)
|
472 | res.end(message)
|
473 | return
|
474 | }
|
475 |
|
476 | if (closing === true) {
|
477 |
|
478 | if (req.httpVersionMajor !== 2) {
|
479 | res.setHeader('Connection', 'close')
|
480 | }
|
481 |
|
482 |
|
483 |
|
484 | if (return503OnClosing) {
|
485 |
|
486 |
|
487 |
|
488 | const headers = {
|
489 | 'Content-Type': 'application/json',
|
490 | 'Content-Length': '80'
|
491 | }
|
492 | res.writeHead(503, headers)
|
493 | res.end('{"error":"Service Unavailable","message":"Service Unavailable","statusCode":503}')
|
494 | childLogger.info({ res: { statusCode: 503 } }, 'request aborted - refusing to accept new requests as server is closing')
|
495 | return
|
496 | }
|
497 | }
|
498 |
|
499 |
|
500 |
|
501 |
|
502 | const connHeader = String.prototype.toLowerCase.call(req.headers.connection || '')
|
503 | if (connHeader === 'keep-alive') {
|
504 | if (keepAliveConnections.has(req.socket) === false) {
|
505 | keepAliveConnections.add(req.socket)
|
506 | req.socket.on('close', removeTrackedSocket.bind({ keepAliveConnections, socket: req.socket }))
|
507 | }
|
508 | }
|
509 |
|
510 |
|
511 | if (req.headers[kRequestAcceptVersion] !== undefined) {
|
512 | req.headers['accept-version'] = req.headers[kRequestAcceptVersion]
|
513 | req.headers[kRequestAcceptVersion] = undefined
|
514 | }
|
515 |
|
516 | const request = new context.Request(id, params, req, query, childLogger, context)
|
517 | const reply = new context.Reply(res, request, childLogger)
|
518 | if (disableRequestLogging === false) {
|
519 | childLogger.info({ req: request }, 'incoming request')
|
520 | }
|
521 |
|
522 | if (hasLogger === true || context.onResponse !== null) {
|
523 | setupResponseListeners(reply)
|
524 | }
|
525 |
|
526 | if (context.onRequest !== null) {
|
527 | onRequestHookRunner(
|
528 | context.onRequest,
|
529 | request,
|
530 | reply,
|
531 | runPreParsing
|
532 | )
|
533 | } else {
|
534 | runPreParsing(null, request, reply)
|
535 | }
|
536 |
|
537 | if (context.onRequestAbort !== null) {
|
538 | req.on('close', () => {
|
539 |
|
540 | if (req.aborted) {
|
541 | onRequestAbortHookRunner(
|
542 | context.onRequestAbort,
|
543 | request,
|
544 | handleOnRequestAbortHooksErrors.bind(null, reply)
|
545 | )
|
546 | }
|
547 | })
|
548 | }
|
549 |
|
550 | if (context.onTimeout !== null) {
|
551 | if (!request.raw.socket._meta) {
|
552 | request.raw.socket.on('timeout', handleTimeout)
|
553 | }
|
554 | request.raw.socket._meta = { context, request, reply }
|
555 | }
|
556 | }
|
557 | }
|
558 |
|
559 | function handleOnRequestAbortHooksErrors (reply, err) {
|
560 | if (err) {
|
561 | reply.log.error({ err }, 'onRequestAborted hook failed')
|
562 | }
|
563 | }
|
564 |
|
565 | function handleTimeout () {
|
566 | const { context, request, reply } = this._meta
|
567 | onTimeoutHookRunner(
|
568 | context.onTimeout,
|
569 | request,
|
570 | reply,
|
571 | noop
|
572 | )
|
573 | }
|
574 |
|
575 | function normalizeAndValidateMethod (method) {
|
576 | if (typeof method !== 'string') {
|
577 | throw new FST_ERR_ROUTE_METHOD_INVALID()
|
578 | }
|
579 | method = method.toUpperCase()
|
580 | if (supportedMethods.indexOf(method) === -1) {
|
581 | throw new FST_ERR_ROUTE_METHOD_NOT_SUPPORTED(method)
|
582 | }
|
583 |
|
584 | return method
|
585 | }
|
586 |
|
587 | function validateSchemaBodyOption (method, path, schema) {
|
588 | if ((method === 'GET' || method === 'HEAD') && schema && schema.body) {
|
589 | throw new FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED(method, path)
|
590 | }
|
591 | }
|
592 |
|
593 | function validateBodyLimitOption (bodyLimit) {
|
594 | if (bodyLimit === undefined) return
|
595 | if (!Number.isInteger(bodyLimit) || bodyLimit <= 0) {
|
596 | throw new FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT(bodyLimit)
|
597 | }
|
598 | }
|
599 |
|
600 | function runPreParsing (err, request, reply) {
|
601 | if (reply.sent === true) return
|
602 | if (err != null) {
|
603 | reply[kReplyIsError] = true
|
604 | reply.send(err)
|
605 | return
|
606 | }
|
607 |
|
608 | request[kRequestPayloadStream] = request.raw
|
609 |
|
610 | if (request[kRouteContext].preParsing !== null) {
|
611 | preParsingHookRunner(request[kRouteContext].preParsing, request, reply, handleRequest)
|
612 | } else {
|
613 | handleRequest(null, request, reply)
|
614 | }
|
615 | }
|
616 |
|
617 |
|
618 |
|
619 |
|
620 |
|
621 |
|
622 | function removeTrackedSocket () {
|
623 | this.keepAliveConnections.delete(this.socket)
|
624 | }
|
625 |
|
626 | function noop () { }
|
627 |
|
628 | module.exports = { buildRouting, validateBodyLimitOption }
|