UNPKG

4.59 kBJavaScriptView Raw
1'use strict'
2
3const assert = require('assert')
4const http = require('http')
5const https = require('https')
6
7const { kState, kOptions } = require('./symbols')
8const {
9 codes: { FST_ERR_HTTP2_INVALID_VERSION }
10} = require('./errors')
11
12function createServer (options, httpHandler) {
13 assert(options, 'Missing options')
14 assert(httpHandler, 'Missing http handler')
15
16 var server = null
17 if (options.serverFactory) {
18 server = options.serverFactory(httpHandler, options)
19 } else if (options.https) {
20 if (options.http2) {
21 server = http2().createSecureServer(options.https, httpHandler)
22 } else {
23 server = https.createServer(options.https, httpHandler)
24 }
25 } else if (options.http2) {
26 server = http2().createServer(httpHandler)
27 } else {
28 server = http.createServer(httpHandler)
29 }
30
31 return { server, listen }
32
33 // `this` is the Fastify object
34 function listen () {
35 const normalizeListenArgs = (args) => {
36 if (args.length === 0) {
37 return { port: 0, host: 'localhost' }
38 }
39
40 const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined
41 const options = { cb: cb }
42
43 const firstArg = args[0]
44 const argsLength = args.length
45 const lastArg = args[argsLength - 1]
46 /* Deal with listen (options) || (handle[, backlog]) */
47 if (typeof firstArg === 'object' && firstArg !== null) {
48 options.backlog = argsLength > 1 ? lastArg : undefined
49 Object.assign(options, firstArg)
50 } else if (typeof firstArg === 'string' && isNaN(firstArg)) {
51 /* Deal with listen (pipe[, backlog]) */
52 options.path = firstArg
53 options.backlog = argsLength > 1 ? lastArg : undefined
54 } else {
55 /* Deal with listen ([port[, host[, backlog]]]) */
56 options.port = argsLength >= 1 && firstArg ? firstArg : 0
57 // This will listen to what localhost is.
58 // It can be 127.0.0.1 or ::1, depending on the operating system.
59 // Fixes https://github.com/fastify/fastify/issues/1022.
60 options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost'
61 options.backlog = argsLength >= 3 ? args[2] : undefined
62 }
63
64 return options
65 }
66
67 const listenOptions = normalizeListenArgs(Array.from(arguments))
68 const cb = listenOptions.cb
69
70 const wrap = err => {
71 server.removeListener('error', wrap)
72 if (!err) {
73 const address = logServerAddress()
74 cb(null, address)
75 } else {
76 this[kState].listening = false
77 cb(err, null)
78 }
79 }
80
81 const listenPromise = (listenOptions) => {
82 if (this[kState].listening) {
83 return Promise.reject(new Error('Fastify is already listening'))
84 }
85
86 return this.ready().then(() => {
87 var errEventHandler
88 var errEvent = new Promise((resolve, reject) => {
89 errEventHandler = (err) => {
90 this[kState].listening = false
91 reject(err)
92 }
93 server.once('error', errEventHandler)
94 })
95 var listen = new Promise((resolve, reject) => {
96 server.listen(listenOptions, () => {
97 server.removeListener('error', errEventHandler)
98 resolve(logServerAddress())
99 })
100 // we set it afterwards because listen can throw
101 this[kState].listening = true
102 })
103
104 return Promise.race([
105 errEvent, // e.g invalid port range error is always emitted before the server listening
106 listen
107 ])
108 })
109 }
110
111 const logServerAddress = () => {
112 var address = server.address()
113 const isUnixSocket = typeof address === 'string'
114 if (!isUnixSocket) {
115 if (address.address.indexOf(':') === -1) {
116 address = address.address + ':' + address.port
117 } else {
118 address = '[' + address.address + ']:' + address.port
119 }
120 }
121 address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address
122 this.log.info('Server listening at ' + address)
123 return address
124 }
125
126 if (cb === undefined) return listenPromise(listenOptions)
127
128 this.ready(err => {
129 if (err != null) return cb(err)
130
131 if (this[kState].listening) {
132 return cb(new Error('Fastify is already listening'), null)
133 }
134
135 server.once('error', wrap)
136 server.listen(listenOptions, wrap)
137
138 this[kState].listening = true
139 })
140 }
141}
142
143function http2 () {
144 try {
145 return require('http2')
146 } catch (err) {
147 throw new FST_ERR_HTTP2_INVALID_VERSION()
148 }
149}
150
151module.exports = { createServer }