function Server(options) {
    assert.object(options, 'options');
    assert.object(options.log, 'options.log');
    assert.object(options.router, 'options.router');
    assert.string(options.name, 'options.name');
    assert.optionalBool(options.dtrace, 'options.dtrace');
    assert.optionalBool(options.socketio, 'options.socketio');
    assert.optionalBool(options.onceNext, 'options.onceNext');
    assert.optionalBool(options.strictNext, 'options.strictNext');
    assert.optionalBool(options.strictFormatters, 'options.strictFormatters');

    var self = this;

    EventEmitter.call(this);

    this.onceNext = !!options.onceNext;
    this.strictNext = !!options.strictNext;
    this.firstChain = [];
    this.preChain = new Chain({
        onceNext: this.onceNext,
        strictNext: this.strictNext
    });
    this.useChain = new Chain({
        onceNext: this.onceNext,
        strictNext: this.strictNext
    });
    this.log = options.log;
    this.name = options.name;
    this.handleUncaughtExceptions = false;
    const { handleUncaughtExceptions } = options;
    if (options.handleUncaughtExceptions) {
        const handleType = typeof handleUncaughtExceptions;
        if (handleType === 'boolean') {
            this.handleUncaughtExceptions = handleWithDomain;
        } else if (handleType === 'function') {
            this.handleUncaughtExceptions = handleUncaughtExceptions;
        } else {
            // prettier-ignore
            // eslint-disable-next-line max-len
            assert.fail(`typeof opts.handleUncaughtException (${handleType}) should be boolean OR function`);
        }
    }
    this.router = options.router;
    this.secure = false;
    this.socketio = options.socketio || false;
    this.dtrace = options.dtrace || false;
    this._inflightRequests = 0;

    this.strictFormatters = true;
    if (options.strictFormatters !== undefined) {
        this.strictFormatters = options.strictFormatters;
    }

    var fmt = mergeFormatters(options.formatters);
    this.acceptable = fmt.acceptable;
    this.formatters = fmt.formatters;
    this.proxyEvents = [
        'close',
        'connection',
        'error',
        'listening',
        'secureConnection'
    ];

    if (options.spdy) {
        spdy = require('spdy');
        this.spdy = true;
        this.server = spdy.createServer(options.spdy);
    } else if (options.http2) {
        // http2 module is not available < v8.4.0 (only with flag <= 8.8.0)
        // load http2 module here to avoid experimental warning in other cases
        if (!http2) {
            try {
                http2 = require('http2');
                patchResponse(http2.Http2ServerResponse);
                patchRequest(http2.Http2ServerRequest);
                // eslint-disable-next-line no-empty
            } catch (err) {}
        }

        assert(
            http2,
            'http2 module is not available, ' +
                'upgrade your Node.js version to >= 8.8.0'
        );

        this.http2 = true;
        this.server = http2.createSecureServer(options.http2);
    } else if ((options.cert || options.certificate) && options.key) {
        this.ca = options.ca;
        this.certificate = options.certificate || options.cert;
        this.key = options.key;
        this.passphrase = options.passphrase || null;
        this.secure = true;

        this.server = https.createServer({
            ca: self.ca,
            cert: self.certificate,
            key: self.key,
            passphrase: self.passphrase,
            rejectUnauthorized: options.rejectUnauthorized,
            requestCert: options.requestCert,
            ciphers: options.ciphers,
            secureOptions: options.secureOptions
        });
    } else if (options.httpsServerOptions) {
        this.server = https.createServer(options.httpsServerOptions);
    } else {
        this.server = http.createServer();
    }

    this.router.on('mount', this.emit.bind(this, 'mount'));

    if (!options.handleUpgrades) {
        this.proxyEvents.push('upgrade');
    }
    this.proxyEvents.forEach(function forEach(e) {
        self.server.on(e, self.emit.bind(self, e));
    });

    // Now the things we can't blindly proxy
    proxyEventWhenListenerAdded('clientError', this, this.server);

    this.server.on('checkContinue', function onCheckContinue(req, res) {
        if (self.listeners('checkContinue').length > 0) {
            self.emit('checkContinue', req, res);
            return;
        }

        if (!options.noWriteContinue) {
            res.writeContinue();
        }

        self._onRequest(req, res);
    });

    if (options.handleUpgrades) {
        this.server.on('upgrade', function onUpgrade(req, socket, head) {
            req._upgradeRequest = true;
            var res = upgrade.createResponse(req, socket, head);
            self._onRequest(req, res);
        });
    }

    this.server.on('request', this._onRequest.bind(this));

    this.__defineGetter__('maxHeadersCount', function getMaxHeadersCount() {
        return self.server.maxHeadersCount;
    });

    this.__defineSetter__('maxHeadersCount', function setMaxHeadersCount(c) {
        self.server.maxHeadersCount = c;
        return c;
    });

    this.__defineGetter__('url', function getUrl() {
        if (self.socketPath) {
            return 'http://' + self.socketPath;
        }

        var addr = self.address();
        var str = '';

        if (self.spdy) {
            str += 'spdy://';
        } else if (self.secure) {
            str += 'https://';
        } else {
            str += 'http://';
        }

        if (addr) {
            str +=
                addr.family === 'IPv6' || addr.family === 6
                    ? '[' + addr.address + ']'
                    : addr.address;
            str += ':';
            str += addr.port;
        } else {
            str += '169.254.0.1:0000';
        }

        return str;
    });

    // print deprecation messages based on server configuration
    deprecationWarnings(self);
}
Creates a new Server.

@public
@class
@param {Object} options  - an options object
@param {String} options.name - Name of the server.
@param {Boolean} [options.dtrace=false] - enable DTrace support
@param {Router} options.router - Router
@param {Object} options.log - [pino](https://github.com/pinojs/pino)
instance.
@param {String} [options.url] - Once listen() is called, this will be filled
in with where the server is running.
@param {String|Buffer} [options.certificate] - If you want to create an HTTPS
server, pass in a PEM-encoded certificate and key.
@param {String|Buffer} [options.key] - If you want to create an HTTPS server,
pass in a PEM-encoded certificate and key.
@param {Object} [options.formatters] - Custom response formatters for
`res.send()`.
@param {Boolean|Function} [options.handleUncaughtExceptions=false] - When
true restify will use a domain to catch and respond to any uncaught
exceptions that occur in its handler stack. Comes with significant negative
performance impact.
Can also receive a function with signature (req, res, onError, next),
allowing for domains alternatives. onError should be called by the custom
error handler, and next must be called at the end of this function. THIS
FUNCTION IS NOT INTENDED TO BE USED TO HANDLE ERRORS DIRECTLY, IT IS ONLY
INTENDED AS AN ALTERNATIVE TO `domains`.
  onError signature: (err, req, res)
  next signature: (res, res)
@param {Object} [options.spdy] - Any options accepted by
[node-spdy](https://github.com/indutny/node-spdy).
@param {Object} [options.http2] - Any options accepted by
[http2.createSecureServer](https://nodejs.org/api/http2.html).
@param {Boolean} [options.handleUpgrades=false] - Hook the `upgrade` event
from the node HTTP server, pushing `Connection: Upgrade` requests through the
 regular request handling chain.
@param {Boolean} [options.onceNext=false] - Prevents calling next multiple
 times
@param {Boolean} [options.strictNext=false] - Throws error when next() is
 called more than once, enabled onceNext option
@param {Object} [options.httpsServerOptions] - Any options accepted by
[node-https Server](http://nodejs.org/api/https.html#https_https).
If provided the following restify server options will be ignored:
spdy, ca, certificate, key, passphrase, rejectUnauthorized, requestCert and
ciphers; however these can all be specified on httpsServerOptions.
@param {Boolean} [options.noWriteContinue=false] - prevents
 `res.writeContinue()` in `server.on('checkContinue')` when proxing
@param {Boolean} [options.ignoreTrailingSlash=false] - ignore trailing slash
on paths
@param {Boolean} [options.strictFormatters=true] - enables strict formatters
behavior: a formatter matching the response's content-type is required. If
not found, the response's content-type is automatically set to
'application/octet-stream'. If a formatter for that content-type is not
found, sending the response errors.
@example
var restify = require('restify');
var server = restify.createServer();

server.listen(8080, function () {
  console.log('ready on %s', server.url);
});