Sindbad~EG File Manager
'use strict'
const VERSION = '3.29.5'
const Avvio = require('avvio')
const http = require('http')
const querystring = require('querystring')
let lightMyRequest
const {
kAvvioBoot,
kChildren,
kBodyLimit,
kRoutePrefix,
kLogLevel,
kLogSerializers,
kHooks,
kSchemaController,
kRequestAcceptVersion,
kReplySerializerDefault,
kContentTypeParser,
kReply,
kRequest,
kFourOhFour,
kState,
kOptions,
kPluginNameChain,
kSchemaErrorFormatter,
kErrorHandler,
kKeepAliveConnections,
kFourOhFourContext
} = require('./lib/symbols.js')
const { createServer } = require('./lib/server')
const Reply = require('./lib/reply')
const Request = require('./lib/request')
const supportedMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS']
const decorator = require('./lib/decorate')
const ContentTypeParser = require('./lib/contentTypeParser')
const SchemaController = require('./lib/schema-controller')
const { Hooks, hookRunnerApplication, supportedHooks } = require('./lib/hooks')
const { createLogger } = require('./lib/logger')
const pluginUtils = require('./lib/pluginUtils')
const reqIdGenFactory = require('./lib/reqIdGenFactory')
const { buildRouting, validateBodyLimitOption } = require('./lib/route')
const build404 = require('./lib/fourOhFour')
const getSecuredInitialConfig = require('./lib/initialConfigValidation')
const override = require('./lib/pluginOverride')
const warning = require('./lib/warnings')
const noopSet = require('./lib/noop-set')
const { defaultInitOptions } = getSecuredInitialConfig
const {
FST_ERR_BAD_URL,
FST_ERR_MISSING_MIDDLEWARE
} = require('./lib/errors')
const onBadUrlContext = {
config: {
},
onSend: [],
onError: [],
[kFourOhFourContext]: null
}
function defaultBuildPrettyMeta (route) {
// return a shallow copy of route's sanitized context
const cleanKeys = {}
const allowedProps = ['errorHandler', 'logLevel', 'logSerializers']
allowedProps.concat(supportedHooks).forEach(k => {
cleanKeys[k] = route.store[k]
})
return Object.assign({}, cleanKeys)
}
function defaultErrorHandler (error, request, reply) {
if (reply.statusCode < 500) {
reply.log.info(
{ res: reply, err: error },
error && error.message
)
} else {
reply.log.error(
{ req: request, res: reply, err: error },
error && error.message
)
}
reply.send(error)
}
function fastify (options) {
// Options validations
options = options || {}
if (typeof options !== 'object') {
throw new TypeError('Options must be an object')
}
if (options.querystringParser && typeof options.querystringParser !== 'function') {
throw new Error(`querystringParser option should be a function, instead got '${typeof options.querystringParser}'`)
}
if (options.schemaController && options.schemaController.bucket && typeof options.schemaController.bucket !== 'function') {
throw new Error(`schemaController.bucket option should be a function, instead got '${typeof options.schemaController.bucket}'`)
}
validateBodyLimitOption(options.bodyLimit)
const requestIdHeader = options.requestIdHeader || defaultInitOptions.requestIdHeader
const querystringParser = options.querystringParser || querystring.parse
const genReqId = options.genReqId || reqIdGenFactory()
const requestIdLogLabel = options.requestIdLogLabel || 'reqId'
const bodyLimit = options.bodyLimit || defaultInitOptions.bodyLimit
const disableRequestLogging = options.disableRequestLogging || false
const exposeHeadRoutes = options.exposeHeadRoutes != null ? options.exposeHeadRoutes : false
const ajvOptions = Object.assign({
customOptions: {},
plugins: []
}, options.ajv)
const frameworkErrors = options.frameworkErrors
// Ajv options
if (!ajvOptions.customOptions || Object.prototype.toString.call(ajvOptions.customOptions) !== '[object Object]') {
throw new Error(`ajv.customOptions option should be an object, instead got '${typeof ajvOptions.customOptions}'`)
}
if (!ajvOptions.plugins || !Array.isArray(ajvOptions.plugins)) {
throw new Error(`ajv.plugins option should be an array, instead got '${typeof ajvOptions.plugins}'`)
}
// Instance Fastify components
const { logger, hasLogger } = createLogger(options)
// Update the options with the fixed values
options.connectionTimeout = options.connectionTimeout || defaultInitOptions.connectionTimeout
options.keepAliveTimeout = options.keepAliveTimeout || defaultInitOptions.keepAliveTimeout
options.forceCloseConnections = typeof options.forceCloseConnections === 'boolean' ? options.forceCloseConnections : defaultInitOptions.forceCloseConnections
options.maxRequestsPerSocket = options.maxRequestsPerSocket || defaultInitOptions.maxRequestsPerSocket
options.requestTimeout = options.requestTimeout || defaultInitOptions.requestTimeout
options.logger = logger
options.genReqId = genReqId
options.requestIdHeader = requestIdHeader
options.querystringParser = querystringParser
options.requestIdLogLabel = requestIdLogLabel
options.disableRequestLogging = disableRequestLogging
options.ajv = ajvOptions
options.clientErrorHandler = options.clientErrorHandler || defaultClientErrorHandler
options.exposeHeadRoutes = exposeHeadRoutes
const initialConfig = getSecuredInitialConfig(options)
const keepAliveConnections = options.forceCloseConnections === true ? new Set() : noopSet()
let constraints = options.constraints
if (options.versioning) {
warning.emit('FSTDEP009')
constraints = {
...constraints,
version: {
name: 'version',
mustMatchWhenDerived: true,
storage: options.versioning.storage,
deriveConstraint: options.versioning.deriveVersion,
validate (value) {
if (typeof value !== 'string') {
throw new Error('Version constraint should be a string.')
}
}
}
}
}
// Default router
const router = buildRouting({
config: {
defaultRoute,
onBadUrl,
constraints,
ignoreTrailingSlash: options.ignoreTrailingSlash || defaultInitOptions.ignoreTrailingSlash,
maxParamLength: options.maxParamLength || defaultInitOptions.maxParamLength,
caseSensitive: options.caseSensitive,
buildPrettyMeta: defaultBuildPrettyMeta
},
keepAliveConnections
})
// 404 router, used for handling encapsulated 404 handlers
const fourOhFour = build404(options)
// HTTP server and its handler
const httpHandler = wrapRouting(router.routing, options)
// we need to set this before calling createServer
options.http2SessionTimeout = initialConfig.http2SessionTimeout
const { server, listen } = createServer(options, httpHandler)
const setupResponseListeners = Reply.setupResponseListeners
const schemaController = SchemaController.buildSchemaController(null, options.schemaController)
// Public API
const fastify = {
// Fastify internals
[kState]: {
listening: false,
closing: false,
started: false
},
[kKeepAliveConnections]: keepAliveConnections,
[kOptions]: options,
[kChildren]: [],
[kBodyLimit]: bodyLimit,
[kRoutePrefix]: '',
[kLogLevel]: '',
[kLogSerializers]: null,
[kHooks]: new Hooks(),
[kSchemaController]: schemaController,
[kSchemaErrorFormatter]: null,
[kErrorHandler]: defaultErrorHandler,
[kReplySerializerDefault]: null,
[kContentTypeParser]: new ContentTypeParser(
bodyLimit,
(options.onProtoPoisoning || defaultInitOptions.onProtoPoisoning),
(options.onConstructorPoisoning || defaultInitOptions.onConstructorPoisoning)
),
[kReply]: Reply.buildReply(Reply),
[kRequest]: Request.buildRequest(Request, options.trustProxy),
[kFourOhFour]: fourOhFour,
[pluginUtils.registeredPlugins]: [],
[kPluginNameChain]: [],
[kAvvioBoot]: null,
// routing method
routing: httpHandler,
getDefaultRoute: router.getDefaultRoute.bind(router),
setDefaultRoute: router.setDefaultRoute.bind(router),
// routes shorthand methods
delete: function _delete (url, opts, handler) {
return router.prepareRoute.call(this, 'DELETE', url, opts, handler)
},
get: function _get (url, opts, handler) {
return router.prepareRoute.call(this, 'GET', url, opts, handler)
},
head: function _head (url, opts, handler) {
return router.prepareRoute.call(this, 'HEAD', url, opts, handler)
},
patch: function _patch (url, opts, handler) {
return router.prepareRoute.call(this, 'PATCH', url, opts, handler)
},
post: function _post (url, opts, handler) {
return router.prepareRoute.call(this, 'POST', url, opts, handler)
},
put: function _put (url, opts, handler) {
return router.prepareRoute.call(this, 'PUT', url, opts, handler)
},
options: function _options (url, opts, handler) {
return router.prepareRoute.call(this, 'OPTIONS', url, opts, handler)
},
all: function _all (url, opts, handler) {
return router.prepareRoute.call(this, supportedMethods, url, opts, handler)
},
// extended route
route: function _route (opts) {
// we need the fastify object that we are producing so we apply a lazy loading of the function,
// otherwise we should bind it after the declaration
return router.route.call(this, opts)
},
// expose logger instance
log: logger,
// hooks
addHook,
// schemas
addSchema,
getSchema: schemaController.getSchema.bind(schemaController),
getSchemas: schemaController.getSchemas.bind(schemaController),
setValidatorCompiler,
setSerializerCompiler,
setSchemaController,
setReplySerializer,
setSchemaErrorFormatter,
// custom parsers
addContentTypeParser: ContentTypeParser.helpers.addContentTypeParser,
hasContentTypeParser: ContentTypeParser.helpers.hasContentTypeParser,
getDefaultJsonParser: ContentTypeParser.defaultParsers.getDefaultJsonParser,
defaultTextParser: ContentTypeParser.defaultParsers.defaultTextParser,
removeContentTypeParser: ContentTypeParser.helpers.removeContentTypeParser,
removeAllContentTypeParsers: ContentTypeParser.helpers.removeAllContentTypeParsers,
// Fastify architecture methods (initialized by Avvio)
register: null,
after: null,
ready: null,
onClose: null,
close: null,
printPlugins: null,
// http server
listen,
server,
// extend fastify objects
decorate: decorator.add,
hasDecorator: decorator.exist,
decorateReply: decorator.decorateReply,
decorateRequest: decorator.decorateRequest,
hasRequestDecorator: decorator.existRequest,
hasReplyDecorator: decorator.existReply,
// fake http injection
inject,
// pretty print of the registered routes
printRoutes,
// custom error handling
setNotFoundHandler,
setErrorHandler,
// Set fastify initial configuration options read-only object
initialConfig
}
fastify[kReply].prototype.server = fastify
fastify[kRequest].prototype.server = fastify
Object.defineProperties(fastify, {
pluginName: {
get () {
if (this[kPluginNameChain].length > 1) {
return this[kPluginNameChain].join(' -> ')
}
return this[kPluginNameChain][0]
}
},
prefix: {
get () { return this[kRoutePrefix] }
},
validatorCompiler: {
get () { return this[kSchemaController].getValidatorCompiler() }
},
serializerCompiler: {
get () { return this[kSchemaController].getSerializerCompiler() }
},
version: {
get () { return VERSION }
},
errorHandler: {
get () {
return this[kErrorHandler]
}
}
})
// We are adding `use` to the fastify prototype so the user
// can still access it (and get the expected error), but `decorate`
// will not detect it, and allow the user to override it.
Object.setPrototypeOf(fastify, { use })
if (options.schemaErrorFormatter) {
validateSchemaErrorFormatter(options.schemaErrorFormatter)
fastify[kSchemaErrorFormatter] = options.schemaErrorFormatter.bind(fastify)
}
// Install and configure Avvio
// Avvio will update the following Fastify methods:
// - register
// - after
// - ready
// - onClose
// - close
const avvio = Avvio(fastify, {
autostart: false,
timeout: Number(options.pluginTimeout) || defaultInitOptions.pluginTimeout,
expose: {
use: 'register'
}
})
// Override to allow the plugin encapsulation
avvio.override = override
avvio.on('start', () => (fastify[kState].started = true))
fastify[kAvvioBoot] = fastify.ready // the avvio ready function
fastify.ready = ready // overwrite the avvio ready function
fastify.printPlugins = avvio.prettyPrint.bind(avvio)
// cache the closing value, since we are checking it in an hot path
avvio.once('preReady', () => {
fastify.onClose((instance, done) => {
fastify[kState].closing = true
router.closeRoutes()
if (fastify[kState].listening) {
// No new TCP connections are accepted
instance.server.close(done)
for (const conn of fastify[kKeepAliveConnections]) {
// We must invoke the destroy method instead of merely unreffing
// the sockets. If we only unref, then the callback passed to
// `fastify.close` will never be invoked; nor will any of the
// registered `onClose` hooks.
conn.destroy()
fastify[kKeepAliveConnections].delete(conn)
}
} else {
done(null)
}
})
})
// Set the default 404 handler
fastify.setNotFoundHandler()
fourOhFour.arrange404(fastify)
router.setup(options, {
avvio,
fourOhFour,
logger,
hasLogger,
setupResponseListeners,
throwIfAlreadyStarted
})
// Delay configuring clientError handler so that it can access fastify state.
server.on('clientError', options.clientErrorHandler.bind(fastify))
try {
const dc = require('diagnostics_channel')
const initChannel = dc.channel('fastify.initialization')
if (initChannel.hasSubscribers) {
initChannel.publish({ fastify })
}
} catch (e) {
// This only happens if `diagnostics_channel` isn't available, i.e. earlier
// versions of Node.js. In that event, we don't care, so ignore the error.
}
return fastify
function throwIfAlreadyStarted (msg) {
if (fastify[kState].started) throw new Error(msg)
}
// HTTP injection handling
// If the server is not ready yet, this
// utility will automatically force it.
function inject (opts, cb) {
// lightMyRequest is dynamically loaded as it seems very expensive
// because of Ajv
if (lightMyRequest === undefined) {
lightMyRequest = require('light-my-request')
}
if (fastify[kState].started) {
if (fastify[kState].closing) {
// Force to return an error
const error = new Error('Server is closed')
if (cb) {
cb(error)
return
} else {
return Promise.reject(error)
}
}
return lightMyRequest(httpHandler, opts, cb)
}
if (cb) {
this.ready(err => {
if (err) cb(err, null)
else lightMyRequest(httpHandler, opts, cb)
})
} else {
return lightMyRequest((req, res) => {
this.ready(function (err) {
if (err) {
res.emit('error', err)
return
}
httpHandler(req, res)
})
}, opts)
}
}
function ready (cb) {
let resolveReady
let rejectReady
// run the hooks after returning the promise
process.nextTick(runHooks)
if (!cb) {
return new Promise(function (resolve, reject) {
resolveReady = resolve
rejectReady = reject
})
}
function runHooks () {
// start loading
fastify[kAvvioBoot]((err, done) => {
if (err || fastify[kState].started) {
manageErr(err)
} else {
hookRunnerApplication('onReady', fastify[kAvvioBoot], fastify, manageErr)
}
done()
})
}
function manageErr (err) {
if (cb) {
if (err) {
cb(err)
} else {
cb(undefined, fastify)
}
} else {
if (err) {
return rejectReady(err)
}
resolveReady(fastify)
}
}
}
function use () {
throw new FST_ERR_MISSING_MIDDLEWARE()
}
// wrapper that we expose to the user for hooks handling
function addHook (name, fn) {
throwIfAlreadyStarted('Cannot call "addHook" when fastify instance is already started!')
if (name === 'onSend' || name === 'preSerialization' || name === 'onError') {
if (fn.constructor.name === 'AsyncFunction' && fn.length === 4) {
throw new Error('Async function has too many arguments. Async hooks should not use the \'done\' argument.')
}
} else if (name === 'onReady') {
if (fn.constructor.name === 'AsyncFunction' && fn.length !== 0) {
throw new Error('Async function has too many arguments. Async hooks should not use the \'done\' argument.')
}
} else if (name !== 'preParsing') {
if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) {
throw new Error('Async function has too many arguments. Async hooks should not use the \'done\' argument.')
}
}
if (name === 'onClose') {
this.onClose(fn)
} else if (name === 'onReady') {
this[kHooks].add(name, fn)
} else {
this.after((err, done) => {
_addHook.call(this, name, fn)
done(err)
})
}
return this
function _addHook (name, fn) {
this[kHooks].add(name, fn)
this[kChildren].forEach(child => _addHook.call(child, name, fn))
}
}
// wrapper that we expose to the user for schemas handling
function addSchema (schema) {
throwIfAlreadyStarted('Cannot call "addSchema" when fastify instance is already started!')
this[kSchemaController].add(schema)
this[kChildren].forEach(child => child.addSchema(schema))
return this
}
function defaultClientErrorHandler (err, socket) {
// In case of a connection reset, the socket has been destroyed and there is nothing that needs to be done.
// https://nodejs.org/api/http.html#http_event_clienterror
if (err.code === 'ECONNRESET' || socket.destroyed) {
return
}
const body = JSON.stringify({
error: http.STATUS_CODES['400'],
message: 'Client Error',
statusCode: 400
})
// Most devs do not know what to do with this error.
// In the vast majority of cases, it's a network error and/or some
// config issue on the load balancer side.
this.log.trace({ err }, 'client error')
// Copying standard node behaviour
// https://github.com/nodejs/node/blob/6ca23d7846cb47e84fd344543e394e50938540be/lib/_http_server.js#L666
// If the socket is not writable, there is no reason to try to send data.
if (socket.writable) {
socket.write(`HTTP/1.1 400 Bad Request\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`)
}
socket.destroy(err)
}
// If the router does not match any route, every request will land here
// req and res are Node.js core objects
function defaultRoute (req, res) {
if (req.headers['accept-version'] !== undefined) {
// we remove the accept-version header for performance result
// because we do not want to go through the constraint checking
// the usage of symbol here to prevent any colision on custom header name
req.headers[kRequestAcceptVersion] = req.headers['accept-version']
req.headers['accept-version'] = undefined
}
fourOhFour.router.lookup(req, res)
}
function onBadUrl (path, req, res) {
if (frameworkErrors) {
const id = genReqId(req)
const childLogger = logger.child({ reqId: id })
childLogger.info({ req }, 'incoming request')
const request = new Request(id, null, req, null, childLogger, onBadUrlContext)
const reply = new Reply(res, request, childLogger)
return frameworkErrors(new FST_ERR_BAD_URL(path), request, reply)
}
const body = `{"error":"Bad Request","message":"'${path}' is not a valid url component","statusCode":400}`
res.writeHead(400, {
'Content-Type': 'application/json',
'Content-Length': body.length
})
res.end(body)
}
function setNotFoundHandler (opts, handler) {
throwIfAlreadyStarted('Cannot call "setNotFoundHandler" when fastify instance is already started!')
fourOhFour.setNotFoundHandler.call(this, opts, handler, avvio, router.routeHandler)
return this
}
function setValidatorCompiler (validatorCompiler) {
throwIfAlreadyStarted('Cannot call "setValidatorCompiler" when fastify instance is already started!')
this[kSchemaController].setValidatorCompiler(validatorCompiler)
return this
}
function setSchemaErrorFormatter (errorFormatter) {
throwIfAlreadyStarted('Cannot call "setSchemaErrorFormatter" when fastify instance is already started!')
validateSchemaErrorFormatter(errorFormatter)
this[kSchemaErrorFormatter] = errorFormatter.bind(this)
return this
}
function setSerializerCompiler (serializerCompiler) {
throwIfAlreadyStarted('Cannot call "setSerializerCompiler" when fastify instance is already started!')
this[kSchemaController].setSerializerCompiler(serializerCompiler)
return this
}
function setSchemaController (schemaControllerOpts) {
throwIfAlreadyStarted('Cannot call "setSchemaController" when fastify instance is already started!')
const old = this[kSchemaController]
const schemaController = SchemaController.buildSchemaController(old, Object.assign({}, old.opts, schemaControllerOpts))
this[kSchemaController] = schemaController
this.getSchema = schemaController.getSchema.bind(schemaController)
this.getSchemas = schemaController.getSchemas.bind(schemaController)
return this
}
function setReplySerializer (replySerializer) {
throwIfAlreadyStarted('Cannot call "setReplySerializer" when fastify instance is already started!')
this[kReplySerializerDefault] = replySerializer
return this
}
// wrapper that we expose to the user for configure the custom error handler
function setErrorHandler (func) {
throwIfAlreadyStarted('Cannot call "setErrorHandler" when fastify instance is already started!')
this[kErrorHandler] = func.bind(this)
return this
}
function printRoutes (opts = {}) {
// includeHooks:true - shortcut to include all supported hooks exported by fastify.Hooks
opts.includeMeta = opts.includeHooks ? opts.includeMeta ? supportedHooks.concat(opts.includeMeta) : supportedHooks : opts.includeMeta
return router.printRoutes(opts)
}
}
function validateSchemaErrorFormatter (schemaErrorFormatter) {
if (typeof schemaErrorFormatter !== 'function') {
throw new Error(`schemaErrorFormatter option should be a function, instead got ${typeof schemaErrorFormatter}`)
} else if (schemaErrorFormatter.constructor.name === 'AsyncFunction') {
throw new Error('schemaErrorFormatter option should not be an async function')
}
}
function wrapRouting (httpHandler, { rewriteUrl, logger }) {
if (!rewriteUrl) {
return httpHandler
}
return function preRouting (req, res) {
const originalUrl = req.url
const url = rewriteUrl(req)
if (originalUrl !== url) {
logger.debug({ originalUrl, url }, 'rewrite url')
if (typeof url === 'string') {
req.url = url
} else {
req.destroy(new Error(`Rewrite url for "${req.url}" needs to be of type "string" but received "${typeof url}"`))
}
}
httpHandler(req, res)
}
}
/**
* These export configurations enable JS and TS developers
* to consumer fastify in whatever way best suits their needs.
* Some examples of supported import syntax includes:
* - `const fastify = require('fastify')`
* - `const { fastify } = require('fastify')`
* - `import * as Fastify from 'fastify'`
* - `import { fastify, TSC_definition } from 'fastify'`
* - `import fastify from 'fastify'`
* - `import fastify, { TSC_definition } from 'fastify'`
*/
module.exports = fastify
module.exports.fastify = fastify
module.exports.default = fastify
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists