diff --git a/README.md b/README.md index a27a3f2e..7b8a9bca 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ This will install `http-server` globally so that it may be run from the command |`--username` |Username for basic authentication | | |`--password` |Password for basic authentication | | -|`-S` or `--ssl` |Enable https.| | +|`-S`, `--tls` or `--ssl` |Enable secure request serving with TLS/SSL (HTTPS)|`false`| |`-C` or `--cert` |Path to ssl cert file |`cert.pem` | |`-K` or `--key` |Path to ssl key file |`key.pem` | |`-r` or `--robots` | Automatically provide a /robots.txt (The content of which defaults to `User-agent: *\nDisallow: /`) | `false` | diff --git a/bin/http-server b/bin/http-server index d424ee81..4aad4404 100755 --- a/bin/http-server +++ b/bin/http-server @@ -7,8 +7,12 @@ var colors = require('colors/safe'), httpServer = require('../lib/http-server'), portfinder = require('portfinder'), opener = require('opener'), - fs = require('fs'), - argv = require('minimist')(process.argv.slice(2)); + fs = require('fs'); +var argv = require('minimist')(process.argv.slice(2), { + alias: { + tls: 'ssl' + } +}); var ifaces = os.networkInterfaces(); process.title = 'http-server'; @@ -38,7 +42,7 @@ if (argv.h || argv.help) { ' -U --utc Use UTC time format in log messages.', ' --log-ip Enable logging of the client\'s IP address', '', - ' -P --proxy Fallback proxy if the request cannot be resolved. e.g.: http://someurl.com', + ' -P --proxy Fallback proxy if the request cannot be resolved. e.g.: http://someurl.com', ' --proxy-options Pass options to proxy using nested dotted objects. e.g.: --proxy-options.secure false', '', ' --username Username for basic authentication [none]', @@ -46,9 +50,9 @@ if (argv.h || argv.help) { ' --password Password for basic authentication [none]', ' Can also be specified with the env variable NODE_HTTP_SERVER_PASSWORD', '', - ' -S --ssl Enable https.', - ' -C --cert Path to ssl cert file (default: cert.pem).', - ' -K --key Path to ssl key file (default: key.pem).', + ' -S --tls --ssl Enable secure request serving with TLS/SSL (HTTPS)', + ' -C --cert Path to TLS cert file (default: cert.pem)', + ' -K --key Path to TLS key file (default: key.pem)', '', ' -r --robots Respond to /robots.txt [User-agent: *\\nDisallow: /]', ' --no-dotfiles Do not show dotfiles', @@ -61,7 +65,7 @@ if (argv.h || argv.help) { var port = argv.p || argv.port || parseInt(process.env.PORT, 10), host = argv.a || '0.0.0.0', - ssl = argv.S || argv.ssl, + tls = argv.S || argv.tls, proxy = argv.P || argv.proxy, proxyOptions = argv['proxy-options'], utc = argv.U || argv.utc, @@ -156,7 +160,7 @@ function listen(port) { } } - if (ssl) { + if (tls) { options.https = { cert: argv.C || argv.cert || 'cert.pem', key: argv.K || argv.key || 'key.pem' @@ -179,16 +183,18 @@ function listen(port) { var server = httpServer.createServer(options); server.listen(port, host, function () { - var protocol = ssl ? 'https://' : 'http://'; + var protocol = tls ? 'https://' : 'http://'; - logger.info([colors.yellow('Starting up http-server, serving '), + logger.info([ + colors.yellow('Starting up http-server, serving '), colors.cyan(server.root), - ssl ? (colors.yellow(' through') + colors.cyan(' https')) : '' + tls ? (colors.yellow(' through') + colors.cyan(' https')) : '' ].join('')); logger.info([colors.yellow('\nhttp-server version: '), colors.cyan(require('../package.json').version)].join('')); - logger.info([colors.yellow('\nhttp-server settings: '), + logger.info([ + colors.yellow('\nhttp-server settings: '), ([colors.yellow('CORS: '), argv.cors ? colors.cyan(argv.cors) : colors.red('disabled')].join('')), ([colors.yellow('Cache: '), argv.c ? (argv.c === '-1' ? colors.red('disabled') : colors.cyan(argv.c + ' seconds')) : colors.cyan('3600 seconds')].join('')), ([colors.yellow('Connection Timeout: '), argv.t === '0' ? colors.red('disabled') : (argv.t ? colors.cyan(argv.t + ' seconds') : colors.cyan('120 seconds'))].join('')), diff --git a/doc/http-server.1 b/doc/http-server.1 index b543064c..d4aa4397 100644 --- a/doc/http-server.1 +++ b/doc/http-server.1 @@ -102,7 +102,7 @@ Can also be specified with the environment variable NODE_HTTP_SERVER_PASSWORD. Defaults to none. .TP -.BI \-S ", " \-\-ssl +.BI \-S ", " \-\-tls ", " \-\-ssl Enable https. .TP diff --git a/lib/http-server.js b/lib/http-server.js index 4b69cffe..a3fdea78 100644 --- a/lib/http-server.js +++ b/lib/http-server.js @@ -33,8 +33,7 @@ function HttpServer(options) { if (options.root) { this.root = options.root; - } - else { + } else { try { fs.lstatSync('./public'); this.root = './public'; diff --git a/package-lock.json b/package-lock.json index 1a11c7e0..c185ed48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "tap": "^14.11.0" }, "engines": { - "node": ">=6" + "node": ">=12" } }, "node_modules/@babel/code-frame": { diff --git a/test/cli.test.js b/test/cli.test.js index 9eebc882..fe12c703 100644 --- a/test/cli.test.js +++ b/test/cli.test.js @@ -6,16 +6,12 @@ const test = require('tap').test; const request = require('request'); const spawn = require('child_process').spawn; const path = require('path'); +const portfinder = require('portfinder'); const node = process.execPath; -const defaultUrl = 'http://localhost'; const defaultPort = 8080; -function getRandomInt(min, max) { - return Math.floor(Math.random() * ((max - min) + 1)) + min; -} - -function startEcstatic(args) { +function startServer(args) { return spawn(node, [require.resolve('../bin/http-server')].concat(args)); } @@ -43,62 +39,44 @@ function tearDown(ps, t) { }); } -const getRandomPort = (() => { - const usedPorts = []; - return () => { - const port = getRandomInt(1025, 65536); - if (usedPorts.indexOf(port) > -1) { - return getRandomPort(); - } - - usedPorts.push(port); - return port; - }; -})(); - -test('setting port via cli - default port', (t) => { - t.plan(2); - - const port = defaultPort; - const options = ['.']; - const ecstatic = startEcstatic(options); - - tearDown(ecstatic, t); - - ecstatic.stdout.on('data', (msg) => { - checkServerIsRunning(`${defaultUrl}:${port}`, msg, t); +const getPort = () => new Promise((resolve, reject) => { + portfinder.getPort((err, port) => { + if (err) reject(err); + resolve(port); }); }); test('setting port via cli - custom port', (t) => { t.plan(2); - const port = getRandomPort(); - const options = ['.', '--port', port]; - const ecstatic = startEcstatic(options); + getPort().then((port) => { + const options = ['.', '--port', port]; + const server = startServer(options); - tearDown(ecstatic, t); + tearDown(server, t); - ecstatic.stdout.on('data', (msg) => { - checkServerIsRunning(`${defaultUrl}:${port}`, msg, t); + server.stdout.on('data', (msg) => { + checkServerIsRunning(`http://localhost:${port}`, msg, t); + }); }); }); test('setting mimeTypes via cli - .types file', (t) => { t.plan(4); - const port = getRandomPort(); - const root = path.resolve(__dirname, 'public/'); - const pathMimetypeFile = path.resolve(__dirname, 'fixtures/custom_mime_type.types'); - const options = [root, '--port', port, '--mimetypes', pathMimetypeFile]; - const ecstatic = startEcstatic(options); + getPort().then((port) => { + const root = path.resolve(__dirname, 'public/'); + const pathMimetypeFile = path.resolve(__dirname, 'fixtures/custom_mime_type.types'); + const options = [root, '--port', port, '--mimetypes', pathMimetypeFile]; + const server = startServer(options); - tearDown(ecstatic, t); + tearDown(server, t); - ecstatic.stdout.on('data', (msg) => { - checkServerIsRunning(`${defaultUrl}:${port}/custom_mime_type.opml`, msg, t, (err, res) => { - t.error(err); - t.equal(res.headers['content-type'], 'application/secret'); + server.stdout.on('data', (msg) => { + checkServerIsRunning(`http://localhost:${port}/custom_mime_type.opml`, msg, t, (err, res) => { + t.error(err); + t.equal(res.headers['content-type'], 'application/secret'); + }); }); }); }); @@ -106,19 +84,20 @@ test('setting mimeTypes via cli - .types file', (t) => { test('setting mimeTypes via cli - directly', (t) => { t.plan(4); - const port = getRandomPort(); - const root = path.resolve(__dirname, 'public/'); - const mimeType = ['--mimetypes', '{ "application/x-my-type": ["opml"] }']; - const options = [root, '--port', port].concat(mimeType); - const ecstatic = startEcstatic(options); + getPort().then((port) => { + const root = path.resolve(__dirname, 'public/'); + const mimeType = ['--mimetypes', '{ "application/x-my-type": ["opml"] }']; + const options = [root, '--port', port].concat(mimeType); + const server = startServer(options); - // TODO: remove error handler - tearDown(ecstatic, t); + // TODO: remove error handler + tearDown(server, t); - ecstatic.stdout.on('data', (msg) => { - checkServerIsRunning(`${defaultUrl}:${port}/custom_mime_type.opml`, msg, t, (err, res) => { - t.error(err); - t.equal(res.headers['content-type'], 'application/x-my-type'); + server.stdout.on('data', (msg) => { + checkServerIsRunning(`http://localhost:${port}/custom_mime_type.opml`, msg, t, (err, res) => { + t.error(err); + t.equal(res.headers['content-type'], 'application/x-my-type'); + }); }); }); }); diff --git a/test/proxy-options.test.js b/test/proxy-options.test.js index 07126925..263d35f3 100644 --- a/test/proxy-options.test.js +++ b/test/proxy-options.test.js @@ -35,6 +35,7 @@ test('proxy options', (t) => { brotli: true, gzip: true }) + // TODO #723 we should use portfinder server.listen(8080, async () => { try { @@ -42,7 +43,7 @@ test('proxy options', (t) => { const proxyServer = httpServer.createServer({ proxy: 'http://localhost:8080', root: path.join(__dirname, 'fixtures'), - ssl: true, + tls: true, https: httpsOpts, proxyOptions: { secure: false