'use strict' const assert = require('assert') const http = require('http') const https = require('https') const { kState, kOptions } = require('./symbols') const { codes: { FST_ERR_HTTP2_INVALID_VERSION } } = require('./errors') function createServer (options, httpHandler) { assert(options, 'Missing options') assert(httpHandler, 'Missing http handler') var server = null if (options.serverFactory) { server = options.serverFactory(httpHandler, options) } else if (options.https) { if (options.http2) { server = http2().createSecureServer(options.https, httpHandler) } else { server = https.createServer(options.https, httpHandler) } } else if (options.http2) { server = http2().createServer(httpHandler) server.on('session', sessionTimeout(options.http2SessionTimeout)) } else { server = http.createServer(httpHandler) } return { server, listen } // `this` is the Fastify object function listen () { const normalizeListenArgs = (args) => { if (args.length === 0) { return { port: 0, host: 'localhost' } } const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined const options = { cb: cb } const firstArg = args[0] const argsLength = args.length const lastArg = args[argsLength - 1] /* Deal with listen (options) || (handle[, backlog]) */ if (typeof firstArg === 'object' && firstArg !== null) { options.backlog = argsLength > 1 ? lastArg : undefined Object.assign(options, firstArg) } else if (typeof firstArg === 'string' && isNaN(firstArg)) { /* Deal with listen (pipe[, backlog]) */ options.path = firstArg options.backlog = argsLength > 1 ? lastArg : undefined } else { /* Deal with listen ([port[, host[, backlog]]]) */ options.port = argsLength >= 1 && firstArg ? firstArg : 0 // This will listen to what localhost is. // It can be 127.0.0.1 or ::1, depending on the operating system. // Fixes https://github.com/fastify/fastify/issues/1022. options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost' options.backlog = argsLength >= 3 ? args[2] : undefined } return options } const listenOptions = normalizeListenArgs(Array.from(arguments)) const cb = listenOptions.cb const wrap = err => { server.removeListener('error', wrap) if (!err) { const address = logServerAddress() cb(null, address) } else { this[kState].listening = false cb(err, null) } } const listenPromise = (listenOptions) => { if (this[kState].listening) { return Promise.reject(new Error('Fastify is already listening')) } return this.ready().then(() => { var errEventHandler var errEvent = new Promise((resolve, reject) => { errEventHandler = (err) => { this[kState].listening = false reject(err) } server.once('error', errEventHandler) }) var listen = new Promise((resolve, reject) => { server.listen(listenOptions, () => { server.removeListener('error', errEventHandler) resolve(logServerAddress()) }) // we set it afterwards because listen can throw this[kState].listening = true }) return Promise.race([ errEvent, // e.g invalid port range error is always emitted before the server listening listen ]) }) } const logServerAddress = () => { var address = server.address() const isUnixSocket = typeof address === 'string' if (!isUnixSocket) { if (address.address.indexOf(':') === -1) { address = address.address + ':' + address.port } else { address = '[' + address.address + ']:' + address.port } } address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address this.log.info('Server listening at ' + address) return address } if (cb === undefined) return listenPromise(listenOptions) this.ready(err => { if (err != null) return cb(err) if (this[kState].listening) { return cb(new Error('Fastify is already listening'), null) } server.once('error', wrap) server.listen(listenOptions, wrap) this[kState].listening = true }) } } function http2 () { try { return require('http2') } catch (err) { throw new FST_ERR_HTTP2_INVALID_VERSION() } } function sessionTimeout (timeout) { return function (session) { session.setTimeout(timeout, close) } } function close () { this.close() } module.exports = { createServer }